

<!doctype html>

<html lang="en" data-content_root="../../../">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>skidl.schematics.route &#8212; SKiDL 2.2.0 documentation</title>
    <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=fa44fd50" />
    <link rel="stylesheet" type="text/css" href="../../../_static/bizstyle.css?v=a66e137f" />
    
    <script src="../../../_static/documentation_options.js?v=b21de401"></script>
    <script src="../../../_static/doctools.js?v=9bcbadda"></script>
    <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../../_static/bizstyle.js"></script>
    <link rel="index" title="Index" href="../../../genindex.html" />
    <link rel="search" title="Search" href="../../../search.html" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <!--[if lt IE 9]>
    <script src="_static/css3-mediaqueries.js"></script>
    <![endif]-->
  </head><body>
    <h1 id="site-title"><a href="../../../../../"><img src="../../../../../images/slim_banner.png" width="100%"></a></h1>
    
    <div class="related" role="navigation" aria-label="Related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../../genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="../../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../../index.html">SKiDL 2.2.0 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../../index.html" accesskey="U">Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.schematics.route</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <h1>Source code for skidl.schematics.route</h1><div class="highlight"><pre>
<span></span><span class="c1"># -*- coding: utf-8 -*-</span>

<span class="c1"># The MIT License (MIT) - Copyright (c) Dave Vandenbout.</span>

<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Autorouter for generating wiring between symbols in a schematic.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">import</span> <span class="nn">copy</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span><span class="p">,</span> <span class="n">defaultdict</span>
<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">chain</span><span class="p">,</span> <span class="n">zip_longest</span>

<span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="n">Part</span>
<span class="kn">from</span> <span class="nn">skidl.utilities</span> <span class="kn">import</span> <span class="n">export_to_all</span><span class="p">,</span> <span class="n">rmv_attr</span>
<span class="kn">from</span> <span class="nn">.debug_draw</span> <span class="kn">import</span> <span class="n">draw_end</span><span class="p">,</span> <span class="n">draw_endpoint</span><span class="p">,</span> <span class="n">draw_routing</span><span class="p">,</span> <span class="n">draw_seg</span><span class="p">,</span> <span class="n">draw_start</span><span class="p">,</span> <span class="n">draw_text</span>
<span class="kn">from</span> <span class="nn">skidl.geometry</span> <span class="kn">import</span> <span class="n">BBox</span><span class="p">,</span> <span class="n">Point</span><span class="p">,</span> <span class="n">Segment</span><span class="p">,</span> <span class="n">Tx</span><span class="p">,</span> <span class="n">Vector</span><span class="p">,</span> <span class="n">tx_rot_90</span>


<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;RoutingFailure&quot;</span><span class="p">,</span> <span class="s2">&quot;GlobalRoutingFailure&quot;</span><span class="p">,</span> <span class="s2">&quot;SwitchboxRoutingFailure&quot;</span><span class="p">]</span>


<span class="c1">###################################################################</span>
<span class="c1">#</span>
<span class="c1"># OVERVIEW OF SCHEMATIC AUTOROUTER</span>
<span class="c1">#</span>
<span class="c1"># The input is a Node containing child nodes and parts, each with a</span>
<span class="c1"># bounding box and an assigned (x,y) position. The following operations</span>
<span class="c1"># are done for each child node, and then for the parts within this node.</span>
<span class="c1">#</span>
<span class="c1"># The edges of each part bbox are extended to form tracks that divide the</span>
<span class="c1"># routing area into a set of four-sided, non-overlapping switchboxes. Each</span>
<span class="c1"># side of a switchbox is a Face, and each Face is a member of two adjoining</span>
<span class="c1"># switchboxes (except those Faces on the boundary of the total</span>
<span class="c1"># routing area.) Each face is adjacent to the six other faces of</span>
<span class="c1"># the two switchboxes it is part of.</span>
<span class="c1">#</span>
<span class="c1"># Each face has a capacity that indicates the number of wires that can</span>
<span class="c1"># cross through it. The capacity is the length of the face divided by the</span>
<span class="c1"># routing grid. (Faces on a part boundary have zero capacity to prevent</span>
<span class="c1"># routing from entering a part.)</span>
<span class="c1">#</span>
<span class="c1"># Each face on a part bbox is assigned terminals associated with the I/O</span>
<span class="c1"># pins of that symbol.</span>
<span class="c1">#</span>
<span class="c1"># After creating the faces and terminals, the global routing phase creates</span>
<span class="c1"># wires that connect the part pins on the nets. Each wire passes from</span>
<span class="c1"># a face of a switchbox to one of the other three faces, either directly</span>
<span class="c1"># across the switchbox to the opposite face or changing direction to</span>
<span class="c1"># either of the right-angle faces. The global router is basically a maze</span>
<span class="c1"># router that uses the switchboxes as high-level grid squares.</span>
<span class="c1">#</span>
<span class="c1"># After global routing, each net has a sequence of switchbox faces</span>
<span class="c1"># through which it will transit. The exact coordinate that each net</span>
<span class="c1"># enters a face is then assigned to create a Terminal.</span>
<span class="c1">#</span>
<span class="c1"># At this point there are a set of switchboxes which have fixed terminals located</span>
<span class="c1"># along their four faces. A greedy switchbox router</span>
<span class="c1"># (https://doi.org/10.1016/0167-9260(85)90029-X)</span>
<span class="c1"># does the detailed routing within each switchbox.</span>
<span class="c1">#</span>
<span class="c1"># The detailed wiring within all the switchboxes is combined and output</span>
<span class="c1"># as the total wiring for the parts in the Node.</span>
<span class="c1">#</span>
<span class="c1">###################################################################</span>


<span class="c1"># Orientations and directions.</span>
<span class="k">class</span> <span class="nc">Orientation</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
    <span class="n">HORZ</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">VERT</span> <span class="o">=</span> <span class="mi">2</span>


<span class="k">class</span> <span class="nc">Direction</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
    <span class="n">LEFT</span> <span class="o">=</span> <span class="mi">3</span>
    <span class="n">RIGHT</span> <span class="o">=</span> <span class="mi">4</span>


<span class="c1"># Put the orientation/direction enums in global space to make using them easier.</span>
<span class="k">for</span> <span class="n">orientation</span> <span class="ow">in</span> <span class="n">Orientation</span><span class="p">:</span>
    <span class="nb">globals</span><span class="p">()[</span><span class="n">orientation</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">orientation</span><span class="o">.</span><span class="n">value</span>
<span class="k">for</span> <span class="n">direction</span> <span class="ow">in</span> <span class="n">Direction</span><span class="p">:</span>
    <span class="nb">globals</span><span class="p">()[</span><span class="n">direction</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">direction</span><span class="o">.</span><span class="n">value</span>


<span class="c1"># Dictionary for storing colors to visually distinguish routed nets.</span>
<span class="n">net_colors</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span>
    <span class="k">lambda</span><span class="p">:</span> <span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">),</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">),</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">))</span>
<span class="p">)</span>


<span class="k">class</span> <span class="nc">NoSwitchBox</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Exception raised when a switchbox cannot be generated.&quot;&quot;&quot;</span>

    <span class="k">pass</span>


<span class="k">class</span> <span class="nc">TerminalClashException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Exception raised when trying to place two terminals at the same coord on a Face.&quot;&quot;&quot;</span>

    <span class="k">pass</span>


<div class="viewcode-block" id="RoutingFailure">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.RoutingFailure">[docs]</a>
<span class="k">class</span> <span class="nc">RoutingFailure</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Exception raised when a net connecting pins cannot be routed.&quot;&quot;&quot;</span>

    <span class="k">pass</span></div>



<div class="viewcode-block" id="GlobalRoutingFailure">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.GlobalRoutingFailure">[docs]</a>
<span class="k">class</span> <span class="nc">GlobalRoutingFailure</span><span class="p">(</span><span class="n">RoutingFailure</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Failure during global routing phase.&quot;&quot;&quot;</span>

    <span class="k">pass</span></div>



<div class="viewcode-block" id="SwitchboxRoutingFailure">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.SwitchboxRoutingFailure">[docs]</a>
<span class="k">class</span> <span class="nc">SwitchboxRoutingFailure</span><span class="p">(</span><span class="n">RoutingFailure</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Failure during switchbox routing phase.&quot;&quot;&quot;</span>

    <span class="k">pass</span></div>



<span class="k">class</span> <span class="nc">Boundary</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Class for indicating a boundary.</span>

<span class="sd">    When a Boundary object is placed in the part attribute of a Face, it</span>
<span class="sd">    indicates the Face is on the outer boundary of the Node routing area</span>
<span class="sd">    and no routes can pass through it.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">pass</span>


<span class="c1"># Boundary object for placing in the bounding Faces of the Node routing area.</span>
<span class="n">boundary</span> <span class="o">=</span> <span class="n">Boundary</span><span class="p">()</span>

<span class="c1"># Absolute coords of all part pins. Used when trimming stub nets.</span>
<span class="n">pin_pts</span> <span class="o">=</span> <span class="p">[]</span>


<span class="k">class</span> <span class="nc">Terminal</span><span class="p">:</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">net</span><span class="p">,</span> <span class="n">face</span><span class="p">,</span> <span class="n">coord</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Terminal on a Face from which a net is routed within a SwitchBox.</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): Net upon which the Terminal resides.</span>
<span class="sd">            face (Face): SwitchBox Face upon which the Terminal resides.</span>
<span class="sd">            coord (int): Absolute position along the track the face is in.</span>

<span class="sd">        Notes:</span>
<span class="sd">            A terminal exists on a Face and is assigned to a net.</span>
<span class="sd">            The terminal&#39;s (x,y) position is determined by the terminal&#39;s</span>
<span class="sd">            absolute coordinate along the track parallel to the face,</span>
<span class="sd">            and by the Face&#39;s absolute coordinate in the orthogonal direction.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="o">=</span> <span class="n">net</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">face</span> <span class="o">=</span> <span class="n">face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">=</span> <span class="n">coord</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">route_pt</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return (x,y) Point for a Terminal on a Face.&quot;&quot;&quot;</span>
        <span class="n">track</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">face</span><span class="o">.</span><span class="n">track</span>
        <span class="k">if</span> <span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">HORZ</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">Point</span><span class="p">(</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_next_terminal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">next_face</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get the terminal on the next face that lies on the same net as this terminal.</span>

<span class="sd">        This method assumes the terminal&#39;s face and the next face are faces of the</span>
<span class="sd">        same switchbox. Hence, they&#39;re either parallel and on opposite sides, or they&#39;re</span>
<span class="sd">        at right angles so they meet at a corner.</span>

<span class="sd">        Args:</span>
<span class="sd">            next_face (Face): Face to search for a terminal on the same net as this.</span>

<span class="sd">        Raises:</span>
<span class="sd">            RoutingFailure: If no terminal exists.</span>

<span class="sd">        Returns:</span>
<span class="sd">            Terminal: The terminal found on the next face.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">from_face</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">face</span>
        <span class="k">if</span> <span class="n">next_face</span><span class="o">.</span><span class="n">track</span> <span class="ow">in</span> <span class="p">(</span><span class="n">from_face</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">from_face</span><span class="o">.</span><span class="n">end</span><span class="p">):</span>
            <span class="c1"># The next face bounds the interval of the terminals&#39;s face, so</span>
            <span class="c1"># they&#39;re at right angles. With right angle faces, we want to</span>
            <span class="c1"># select a terminal on the next face that&#39;s close to this corner</span>
            <span class="c1"># because that will minimize the length of wire needed to make</span>
            <span class="c1"># the connection.</span>
            <span class="k">if</span> <span class="n">next_face</span><span class="o">.</span><span class="n">beg</span> <span class="o">==</span> <span class="n">from_face</span><span class="o">.</span><span class="n">track</span><span class="p">:</span>
                <span class="c1"># next_face is oriented upward or rightward w.r.t. from_face.</span>
                <span class="c1"># Start searching for a terminal from the lowest index</span>
                <span class="c1"># because this is closest to the corner.</span>
                <span class="n">search_terminals</span> <span class="o">=</span> <span class="n">next_face</span><span class="o">.</span><span class="n">terminals</span>
            <span class="k">elif</span> <span class="n">next_face</span><span class="o">.</span><span class="n">end</span> <span class="o">==</span> <span class="n">from_face</span><span class="o">.</span><span class="n">track</span><span class="p">:</span>
                <span class="c1"># next_face is oriented downward or leftward w.r.t. from_face.</span>
                <span class="c1"># Start searching for a terminal from the highest index</span>
                <span class="c1"># because this is closest to the corner.</span>
                <span class="n">search_terminals</span> <span class="o">=</span> <span class="n">next_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">GlobalRoutingFailure</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># The next face must be the parallel face on the other side of the</span>
            <span class="c1"># switchbox. With parallel faces, we want to selected a terminal</span>
            <span class="c1"># having close to the same position as the given terminal.</span>
            <span class="c1"># So if the given terminal is at position i, then search for the</span>
            <span class="c1"># next terminal on the other face at positions i, i+1, i-1, i+2, i-2...</span>
            <span class="n">coord</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span>
            <span class="n">lower_terminals</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">next_face</span><span class="o">.</span><span class="n">terminals</span> <span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">coord</span><span class="p">]</span>
            <span class="n">lower_terminals</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">t</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="n">upper_terminals</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">next_face</span><span class="o">.</span><span class="n">terminals</span> <span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">coord</span> <span class="o">&gt;</span> <span class="n">coord</span><span class="p">]</span>
            <span class="n">upper_terminals</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">t</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
            <span class="n">search_terminals</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span>
                <span class="n">chain</span><span class="p">(</span><span class="o">*</span><span class="n">zip_longest</span><span class="p">(</span><span class="n">lower_terminals</span><span class="p">,</span> <span class="n">upper_terminals</span><span class="p">))</span>
            <span class="p">)</span>
            <span class="n">search_terminals</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">search_terminals</span> <span class="k">if</span> <span class="n">t</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">]</span>

        <span class="c1"># Search to find a terminal on the same net.</span>
        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">search_terminals</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">terminal</span>  <span class="c1"># Return found terminal.</span>

        <span class="c1"># No terminal on the same net, so search to find an unassigned terminal.</span>
        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">search_terminals</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span>  <span class="c1"># Assign net to terminal.</span>
                <span class="k">return</span> <span class="n">terminal</span>  <span class="c1"># Return newly-assigned terminal.</span>

        <span class="c1"># Well, something went wrong. Should have found *something*!</span>
        <span class="k">raise</span> <span class="n">GlobalRoutingFailure</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw a Terminal for debugging purposes.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (PyGame screen): Screen object for PyGame drawing.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Don&#39;t draw terminal if it isn&#39;t on a net. It&#39;s just a placeholder.</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="ow">or</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_all_terminals&quot;</span><span class="p">):</span>
            <span class="n">draw_endpoint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">route_pt</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
            <span class="c1"># draw_endpoint(self.route_pt, scr, tx, color=net_colors[self.net])</span>


<span class="k">class</span> <span class="nc">Interval</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Define an interval with a beginning and an end.</span>

<span class="sd">        Args:</span>
<span class="sd">            beg (GlobalTrack): Beginning orthogonal track that bounds interval.</span>
<span class="sd">            end (GlobalTrack): Ending orthogonal track that bounds interval.</span>

<span class="sd">        Note: The beginning and ending Tracks are orthogonal to the Track containing the interval.</span>
<span class="sd">              Also, beg and end are sorted so beg &lt;= end.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Order beginning and end so beginning &lt;= end.</span>
        <span class="k">if</span> <span class="n">beg</span> <span class="o">&gt;</span> <span class="n">end</span><span class="p">:</span>
            <span class="n">beg</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="n">end</span><span class="p">,</span> <span class="n">beg</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">beg</span> <span class="o">=</span> <span class="n">beg</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">end</span> <span class="o">=</span> <span class="n">end</span>

    <span class="k">def</span> <span class="fm">__bool__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;An Interval object always returns True.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="kc">True</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">len</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the length of the interval.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the length of the interval.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">len</span>

    <span class="k">def</span> <span class="nf">intersects</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if the intervals overlap (even if only at one point).&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="ow">not</span> <span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span> <span class="o">&gt;</span> <span class="n">other</span><span class="o">.</span><span class="n">end</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span> <span class="o">&lt;</span> <span class="n">other</span><span class="o">.</span><span class="n">beg</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">interval_intersection</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return intersection of two intervals as an interval, otherwise None.&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">other</span><span class="p">):</span>
            <span class="n">beg</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">beg</span><span class="p">)</span>
            <span class="n">end</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">end</span><span class="p">)</span>
            <span class="k">assert</span> <span class="n">beg</span> <span class="o">&lt;=</span> <span class="n">end</span>
            <span class="k">if</span> <span class="n">beg</span> <span class="o">!=</span> <span class="n">end</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">Interval</span><span class="p">(</span><span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="k">def</span> <span class="nf">merge</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return a merged interval if the given intervals intersect, otherwise return None.&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">Interval</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
            <span class="k">return</span> <span class="n">Interval</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">beg</span><span class="p">),</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">end</span><span class="p">))</span>
        <span class="k">return</span> <span class="kc">None</span>


<span class="k">class</span> <span class="nc">NetInterval</span><span class="p">(</span><span class="n">Interval</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">net</span><span class="p">,</span> <span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Define an Interval with an associated net (useful for wire traces in a switchbox).</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): Net associated with interval.</span>
<span class="sd">            beg (GlobalTrack): Beginning orthogonal track that bounds interval.</span>
<span class="sd">            end (GlobalTrack): Ending track that bounds interval.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="o">=</span> <span class="n">net</span>

    <span class="k">def</span> <span class="nf">obstructs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if the intervals intersect and have different nets.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">other</span><span class="o">.</span><span class="n">net</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">merge</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return a merged interval if the given intervals intersect and are on the same net, otherwise return None.&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="n">other</span><span class="o">.</span><span class="n">net</span><span class="p">:</span>
            <span class="n">merged_intvl</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">merged_intvl</span><span class="p">:</span>
                <span class="n">merged_intvl</span> <span class="o">=</span> <span class="n">NetInterval</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">net</span><span class="p">,</span> <span class="n">merged_intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">merged_intvl</span><span class="o">.</span><span class="n">end</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">merged_intvl</span>
        <span class="k">return</span> <span class="kc">None</span>


<span class="k">class</span> <span class="nc">Adjacency</span><span class="p">:</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">from_face</span><span class="p">,</span> <span class="n">to_face</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Define an adjacency between two Faces.</span>

<span class="sd">        Args:</span>
<span class="sd">            from_face (Face): One Face.</span>
<span class="sd">            to_face (Face): The other Face.</span>

<span class="sd">        Note: The Adjacency object will be associated with the from_face object, so there&#39;s</span>
<span class="sd">            no need to store from_face in the Adjacency object.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">face</span> <span class="o">=</span> <span class="n">to_face</span>
        <span class="k">if</span> <span class="n">from_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">to_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span><span class="p">:</span>
            <span class="c1"># Parallel faces, either both vertical or horizontal.</span>
            <span class="c1"># Distance straight-across from one face to the other.</span>
            <span class="n">dist_a</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">from_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span> <span class="o">-</span> <span class="n">to_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
            <span class="c1"># Average distance parallel to the faces.</span>
            <span class="n">dist_b</span> <span class="o">=</span> <span class="p">(</span><span class="n">from_face</span><span class="o">.</span><span class="n">length</span> <span class="o">+</span> <span class="n">to_face</span><span class="o">.</span><span class="n">length</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
            <span class="c1"># Compute the average distance from a terminal on one face to the other.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">dist</span> <span class="o">=</span> <span class="n">dist_a</span> <span class="o">+</span> <span class="n">dist_b</span> <span class="o">/</span> <span class="mi">2</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># Else, orthogonal faces.</span>
            <span class="c1"># Compute the average face-to-face distance.</span>
            <span class="n">dist_a</span> <span class="o">=</span> <span class="n">from_face</span><span class="o">.</span><span class="n">length</span>
            <span class="n">dist_b</span> <span class="o">=</span> <span class="n">to_face</span><span class="o">.</span><span class="n">length</span>
            <span class="c1"># Average distance of dogleg route from a terminal on one face to the other.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">dist</span> <span class="o">=</span> <span class="p">(</span><span class="n">dist_a</span> <span class="o">+</span> <span class="n">dist_b</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>


<span class="k">class</span> <span class="nc">Face</span><span class="p">(</span><span class="n">Interval</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;A side of a rectangle bounding a routing switchbox.&quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">part</span><span class="p">,</span> <span class="n">track</span><span class="p">,</span> <span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;One side of a routing switchbox.</span>

<span class="sd">        Args:</span>
<span class="sd">            part (set,Part,Boundary): Element(s) the Face is part of.</span>
<span class="sd">            track (GlobalTrack): Horz/vert track the Face is on.</span>
<span class="sd">            beg (GlobalTrack): Vert/horz track the Face begins at.</span>
<span class="sd">            end (GlobalTrack): Vert/horz track the Face ends at.</span>

<span class="sd">        Notes:</span>
<span class="sd">            The beg and end tracks have to be in the same direction</span>
<span class="sd">            (i.e., both vertical or both horizontal) and orthogonal</span>
<span class="sd">            to the track containing the face.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Initialize the interval beginning and ending defining the Face.</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">)</span>

        <span class="c1"># Store Part/Boundary the Face is part of, if any.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">part</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="nb">set</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">part</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>

        <span class="c1"># Storage for any part pins that lie along this Face.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pins</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Storage for routing terminals along this face.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Set of Faces adjacent to this one. (Starts empty.)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">adjacent</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># Add this new face to the track it belongs to so it isn&#39;t lost.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">track</span> <span class="o">=</span> <span class="n">track</span>
        <span class="n">track</span><span class="o">.</span><span class="n">add_face</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>

        <span class="c1"># Storage for switchboxes this face is part of.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">switchboxes</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">combine</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Combine information from other face into this one.</span>

<span class="sd">        Args:</span>
<span class="sd">            other (Face): Other Face.</span>

<span class="sd">        Returns:</span>
<span class="sd">            None.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">pins</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">pins</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">terminals</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">part</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">adjacent</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">adjacent</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">switchboxes</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">length</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the length of the face.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">bbox</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the bounding box of the 1-D face segment.&quot;&quot;&quot;</span>
        <span class="n">bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">()</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">VERT</span><span class="p">:</span>
            <span class="c1"># Face runs vertically, so bbox width is zero.</span>
            <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">))</span>
            <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># Face runs horizontally, so bbox height is zero.</span>
            <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">))</span>
            <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">))</span>

        <span class="k">return</span> <span class="n">bbox</span>

    <span class="k">def</span> <span class="nf">add_terminal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">net</span><span class="p">,</span> <span class="n">coord</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create a Terminal on the Face.</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): The net the terminal is on.</span>
<span class="sd">            coord (int): The absolute coordinate along the track containing the Face.</span>

<span class="sd">        Raises:</span>
<span class="sd">            TerminalClashException:</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">part</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">net</span><span class="p">:</span>
            <span class="c1"># Don&#39;t add pin terminals with no net to a Face on a part or boundary.</span>
            <span class="k">return</span>

        <span class="c1"># Search for pre-existing terminal at the same coordinate.</span>
        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="o">==</span> <span class="n">coord</span><span class="p">:</span>
                <span class="c1"># There is a pre-existing terminal at this coord.</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">net</span><span class="p">:</span>
                    <span class="c1"># The new terminal has no net (i.e., non-pin terminal),</span>
                    <span class="c1"># so just quit and don&#39;t bother to add it. The pre-existing</span>
                    <span class="c1"># terminal is retained.</span>
                    <span class="k">return</span>
                <span class="k">elif</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="ow">and</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">net</span><span class="p">:</span>
                    <span class="c1"># The pre-existing and new terminals have differing nets, so</span>
                    <span class="c1"># raise an exception.</span>
                    <span class="k">raise</span> <span class="n">TerminalClashException</span>
                <span class="c1"># The pre-existing and new terminals have the same net.</span>
                <span class="c1"># Remove the pre-existing terminal. It will be replaced</span>
                <span class="c1"># with the new terminal below.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">terminal</span><span class="p">)</span>

        <span class="c1"># Create a new Terminal and add it to the list of terminals for this face.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Terminal</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="n">coord</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">trim_repeated_terminals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove all but one terminal of each individual net from the face.</span>

<span class="sd">        Notes:</span>
<span class="sd">            A non-part Face with multiple terminals on the same net will lead</span>
<span class="sd">            to multi-path routing.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Find the intersection of every non-part face in the track with this one.</span>
        <span class="n">intersections</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                <span class="n">intersection</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">interval_intersection</span><span class="p">(</span><span class="n">face</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">intersection</span><span class="p">:</span>
                    <span class="n">intersections</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">intersection</span><span class="p">)</span>

        <span class="c1"># Merge any overlapping intersections to create larger ones.</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">intersections</span><span class="p">)):</span>
            <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">intersections</span><span class="p">)):</span>
                <span class="n">merge</span> <span class="o">=</span> <span class="n">intersections</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">intersections</span><span class="p">[</span><span class="n">j</span><span class="p">])</span>
                <span class="k">if</span> <span class="n">merge</span><span class="p">:</span>
                    <span class="n">intersections</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">merge</span>
                    <span class="n">intersections</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                    <span class="k">break</span>

        <span class="c1"># Remove None from the list of intersections.</span>
        <span class="n">intersections</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">intersections</span><span class="p">)</span> <span class="o">-</span> <span class="p">{</span><span class="kc">None</span><span class="p">})</span>

        <span class="c1"># The intersections are now as large as they can be and not associated</span>
        <span class="c1"># with any parts, so there are no terminals associated with part pins.</span>
        <span class="c1"># Look for terminals within an intersection on the same net and</span>
        <span class="c1"># remove all but one of them.</span>
        <span class="k">for</span> <span class="n">intersection</span> <span class="ow">in</span> <span class="n">intersections</span><span class="p">:</span>
            <span class="c1"># Make a dict with nets and the terminals on each one.</span>
            <span class="n">net_term_dict</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">intersection</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">intersection</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">:</span>
                    <span class="n">net_term_dict</span><span class="p">[</span><span class="n">terminal</span><span class="o">.</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">terminal</span><span class="p">)</span>
            <span class="k">if</span> <span class="kc">None</span> <span class="ow">in</span> <span class="n">net_term_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
                <span class="k">del</span> <span class="n">net_term_dict</span><span class="p">[</span><span class="kc">None</span><span class="p">]</span>  <span class="c1"># Get rid of terminals not assigned to nets.</span>

            <span class="c1"># For each multi-terminal net, remove all but one terminal.</span>
            <span class="c1"># This terminal must be removed from all faces on the track.</span>
            <span class="k">for</span> <span class="n">terminals</span> <span class="ow">in</span> <span class="n">net_term_dict</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">terminals</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>  <span class="c1"># Keep only the 1st terminal.</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">remove_terminal</span><span class="p">(</span><span class="n">terminal</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">create_nonpin_terminals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create unassigned terminals along a non-part Face with GRID spacing.</span>

<span class="sd">        These terminals will be used during global routing of nets from</span>
<span class="sd">        face-to-face and during switchbox routing.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Add terminals along a Face. A terminal can be right at the start if the Face</span>
        <span class="c1"># starts on a grid point, but there cannot be a terminal at the end</span>
        <span class="c1"># if the Face ends on a grid point. Otherwise, there would be two terminals</span>
        <span class="c1"># at exactly the same point (one at the ending point of a Face and the</span>
        <span class="c1"># other at the beginning point of the next Face).</span>
        <span class="c1"># FIXME: This seems to cause wiring with a lot of doglegs.</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">GRID</span><span class="p">:</span>
            <span class="c1"># Allow a terminal right at the start of the Face if the Face is small.</span>
            <span class="n">beg</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span> <span class="o">+</span> <span class="n">GRID</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">//</span> <span class="n">GRID</span> <span class="o">*</span> <span class="n">GRID</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># For larger faces with lengths greater than the GRID spacing,</span>
            <span class="c1"># don&#39;t allow terminals right at the start of the Face.</span>
            <span class="n">beg</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span> <span class="o">+</span> <span class="n">GRID</span><span class="p">)</span> <span class="o">//</span> <span class="n">GRID</span> <span class="o">*</span> <span class="n">GRID</span>
        <span class="n">end</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span>

        <span class="c1"># Create terminals along the Face.</span>
        <span class="k">for</span> <span class="n">coord</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">,</span> <span class="n">GRID</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">add_terminal</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">set_capacity</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set the wire routing capacity of a Face.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
            <span class="c1"># Part/boundary faces have zero capacity for wires to pass thru.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># Wire routing capacity for other faces is the number of terminals they have.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">has_nets</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if any Terminal on the Face is attached to a net.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">any</span><span class="p">((</span><span class="n">terminal</span><span class="o">.</span><span class="n">net</span> <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">add_adjacencies</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add adjacent faces of the switchbox having this face as the top face.&quot;&quot;&quot;</span>

        <span class="c1"># Create a temporary switchbox.</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">swbx</span> <span class="o">=</span> <span class="n">SwitchBox</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="k">except</span> <span class="n">NoSwitchBox</span><span class="p">:</span>
            <span class="c1"># This face doesn&#39;t belong to a valid switchbox.</span>
            <span class="k">return</span>

        <span class="k">def</span> <span class="nf">add_adjacency</span><span class="p">(</span><span class="n">from_</span><span class="p">,</span> <span class="n">to</span><span class="p">):</span>
            <span class="c1"># Faces on the boundary can never accept wires so they are never</span>
            <span class="c1"># adjacent to any other face.</span>
            <span class="k">if</span> <span class="n">boundary</span> <span class="ow">in</span> <span class="n">from_</span><span class="o">.</span><span class="n">part</span> <span class="ow">or</span> <span class="n">boundary</span> <span class="ow">in</span> <span class="n">to</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                <span class="k">return</span>

            <span class="c1"># If a face is an edge of a part, then it can never be adjacent to</span>
            <span class="c1"># another face on the *same part* or else wires might get routed over</span>
            <span class="c1"># the part bounding box.</span>
            <span class="k">if</span> <span class="n">from_</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="n">to</span><span class="o">.</span><span class="n">part</span><span class="p">):</span>
                <span class="k">return</span>

            <span class="c1"># OK, no parts in common between the two faces so they can be adjacent.</span>
            <span class="n">from_</span><span class="o">.</span><span class="n">adjacent</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Adjacency</span><span class="p">(</span><span class="n">from_</span><span class="p">,</span> <span class="n">to</span><span class="p">))</span>
            <span class="n">to</span><span class="o">.</span><span class="n">adjacent</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Adjacency</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">from_</span><span class="p">))</span>

        <span class="c1"># Add adjacent faces.</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">top_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">)</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">left_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">right_face</span><span class="p">)</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">left_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">top_face</span><span class="p">)</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">left_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">)</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">right_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">top_face</span><span class="p">)</span>
        <span class="n">add_adjacency</span><span class="p">(</span><span class="n">swbx</span><span class="o">.</span><span class="n">right_face</span><span class="p">,</span> <span class="n">swbx</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">)</span>

        <span class="c1"># Get rid of the temporary switchbox.</span>
        <span class="k">del</span> <span class="n">swbx</span>

    <span class="k">def</span> <span class="nf">extend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orthogonal_tracks</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Extend a Face along its track until it is blocked by an orthogonal face.</span>

<span class="sd">        This is used to create Faces that form the irregular grid of switchboxes.</span>

<span class="sd">        Args:</span>
<span class="sd">            orthogonal_tracks (list): List of tracks at right-angle to this face.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Only extend faces that compose part bounding boxes.</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
            <span class="k">return</span>

        <span class="c1"># Extend the face backward from its beginning and forward from its end.</span>
        <span class="k">for</span> <span class="n">start</span><span class="p">,</span> <span class="nb">dir</span> <span class="ow">in</span> <span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="p">,</span> <span class="mi">1</span><span class="p">)):</span>
            <span class="c1"># Get tracks to extend face towards.</span>
            <span class="n">search_tracks</span> <span class="o">=</span> <span class="n">orthogonal_tracks</span><span class="p">[</span><span class="n">start</span><span class="o">.</span><span class="n">idx</span> <span class="p">::</span> <span class="nb">dir</span><span class="p">]</span>

            <span class="c1"># The face extension starts off non-blocked by any orthogonal faces.</span>
            <span class="n">blocked</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1"># Search for a orthogonal face in a track that intersects this extension.</span>
            <span class="k">for</span> <span class="n">ortho_track</span> <span class="ow">in</span> <span class="n">search_tracks</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">ortho_face</span> <span class="ow">in</span> <span class="n">ortho_track</span><span class="p">:</span>
                    <span class="c1"># Intersection only occurs if the extending face hits the open</span>
                    <span class="c1"># interval of the orthogonal face, not if it touches an endpoint.</span>
                    <span class="k">if</span> <span class="n">ortho_face</span><span class="o">.</span><span class="n">beg</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span> <span class="o">&lt;</span> <span class="n">ortho_face</span><span class="o">.</span><span class="n">end</span><span class="p">:</span>
                        <span class="c1"># OK, this face intersects the extension. It also means the</span>
                        <span class="c1"># extending face will block the face just found, so split</span>
                        <span class="c1"># each track at the intersection point.</span>
                        <span class="n">ortho_track</span><span class="o">.</span><span class="n">add_split</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="p">)</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">add_split</span><span class="p">(</span><span class="n">ortho_track</span><span class="p">)</span>

                        <span class="c1"># If the intersecting face is also a face of a part bbox,</span>
                        <span class="c1"># then the extension is blocked, so create the extended face</span>
                        <span class="c1"># and stop the extension.</span>
                        <span class="k">if</span> <span class="n">ortho_face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                            <span class="c1"># This creates a face and adds it to the track.</span>
                            <span class="n">Face</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">ortho_track</span><span class="p">)</span>
                            <span class="n">blocked</span> <span class="o">=</span> <span class="kc">True</span>

                        <span class="c1"># Stop checking faces in this track after an intersection is found.</span>
                        <span class="k">break</span>

                <span class="c1"># Stop checking any further tracks once the face extension is blocked.</span>
                <span class="k">if</span> <span class="n">blocked</span><span class="p">:</span>
                    <span class="k">break</span>

    <span class="k">def</span> <span class="nf">split</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trk</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;If a track intersects in the middle of a face, split the face into two faces.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span> <span class="o">&lt;</span> <span class="n">trk</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="p">:</span>
            <span class="c1"># Add a Face from beg to trk to self.track.</span>
            <span class="n">Face</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">part</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">trk</span><span class="p">)</span>
            <span class="c1"># Move the beginning of the original Face to trk.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">beg</span> <span class="o">=</span> <span class="n">trk</span>

    <span class="k">def</span> <span class="nf">coincides_with</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other_face</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if both faces have the same beginning and ending point on the same track.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">other_face</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">other_face</span><span class="o">.</span><span class="n">end</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">has_overlap</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other_face</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if the two faces overlap.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span> <span class="o">&lt;</span> <span class="n">other_face</span><span class="o">.</span><span class="n">end</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span> <span class="o">&gt;</span> <span class="n">other_face</span><span class="o">.</span><span class="n">beg</span>

    <span class="k">def</span> <span class="nf">audit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Raise exception if face is malformed.&quot;&quot;&quot;</span>
        <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">switchboxes</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">2</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">seg</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return a Segment that coincides with the Face.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">VERT</span><span class="p">:</span>
            <span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
            <span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
            <span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">Segment</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">),</span> <span class="n">thickness</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw a Face in the drawing area.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (PyGame screen): Screen object for PyGame drawing.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            font (PyGame font): Font for rendering text.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values.</span>

<span class="sd">        Returns:</span>
<span class="sd">            None.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Draw a line segment for the Face.</span>
        <span class="n">draw_seg</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">seg</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="o">=</span><span class="n">thickness</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="n">dot_radius</span>
        <span class="p">)</span>

        <span class="c1"># Draw the terminals on the Face.</span>
        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">terminals</span><span class="p">:</span>
            <span class="n">terminal</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;show_capacities&quot;</span><span class="p">):</span>
            <span class="c1"># Show the wiring capacity at the midpoint of the Face.</span>
            <span class="n">mid_pt</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
            <span class="n">draw_text</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">capacity</span><span class="p">),</span> <span class="n">mid_pt</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="o">=</span><span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">GlobalWire</span><span class="p">(</span><span class="nb">list</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">net</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;A list connecting switchbox faces and terminals.</span>

<span class="sd">        Global routes start off as a sequence of switchbox faces that the route</span>
<span class="sd">        goes thru. Later, these faces are converted to terminals at fixed positions</span>
<span class="sd">        on their respective faces.</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): The net associated with the wire.</span>
<span class="sd">            *args: Positional args passed to list superclass __init__().</span>
<span class="sd">            **kwargs: Keyword args passed to list superclass __init__().</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="o">=</span> <span class="n">net</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">cvt_faces_to_terminals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Convert global face-to-face route to switchbox terminal-to-terminal route.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">:</span>
            <span class="c1"># Global route is empty so do nothing.</span>
            <span class="k">return</span>

        <span class="c1"># Non-empty global routes should always start from a face on a part.</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">part</span>

        <span class="c1"># All part faces already have terminals created from the part pins. Find all</span>
        <span class="c1"># the route faces on part boundaries and convert them to pin terminals if</span>
        <span class="c1"># one or more pins are attached to the same net as the route.</span>
        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">face</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="p">[:]):</span>
            <span class="k">if</span> <span class="n">face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                <span class="c1"># This route face is on a part boundary, so find the terminal with the route&#39;s net.</span>
                <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">face</span><span class="o">.</span><span class="n">terminals</span><span class="p">:</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span><span class="p">:</span>
                        <span class="c1"># Replace the route face with the terminal on the part.</span>
                        <span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">terminal</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># Route should never touch a part face if there is no terminal with the route&#39;s net.</span>
                    <span class="k">raise</span> <span class="ne">RuntimeError</span>

        <span class="c1"># Proceed through all the Faces/Terminals on the GlobalWire, converting</span>
        <span class="c1"># all the Faces to Terminals.</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
            <span class="c1"># The current element on a GlobalWire should always be a Terminal. Use that terminal</span>
            <span class="c1"># to convert the next Face on the wire to a Terminal (if it isn&#39;t one already).</span>
            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">Face</span><span class="p">):</span>
                <span class="c1"># Logic error if the current element has not been converted to a Terminal.</span>
                <span class="k">raise</span> <span class="ne">RuntimeError</span>

            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="n">Face</span><span class="p">):</span>
                <span class="c1"># Convert the next Face element into a Terminal on this net. This terminal will</span>
                <span class="c1"># be the current element on the next iteration.</span>
                <span class="bp">self</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">get_next_terminal</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">thickness</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw a global wire from Face-to-Face in the drawing area.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (PyGame screen): Screen object for PyGame drawing.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            color (list): Three-element list of RGB integers with range [0, 255].</span>
<span class="sd">            thickness (int): Thickness of drawn wire in pixels.</span>
<span class="sd">            dot_radius (int): Radius of drawn terminal in pixels.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>

<span class="sd">        Returns:</span>
<span class="sd">            None.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Draw pins on the net associated with the wire.</span>
        <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">net</span><span class="o">.</span><span class="n">pins</span><span class="p">:</span>
            <span class="c1"># Only draw pins in the current node being routed which have the route_pt attribute.</span>
            <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="s2">&quot;route_pt&quot;</span><span class="p">):</span>
                <span class="n">pt</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>
                <span class="n">track</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">face</span><span class="o">.</span><span class="n">track</span>
                <span class="n">pt</span> <span class="o">=</span> <span class="p">{</span>
                    <span class="n">HORZ</span><span class="p">:</span> <span class="n">Point</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">),</span>
                    <span class="n">VERT</span><span class="p">:</span> <span class="n">Point</span><span class="p">(</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span><span class="p">),</span>
                <span class="p">}[</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span><span class="p">]</span>
                <span class="n">draw_endpoint</span><span class="p">(</span><span class="n">pt</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>

        <span class="c1"># Draw global wire segment.</span>
        <span class="n">face_to_face</span> <span class="o">=</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
        <span class="k">for</span> <span class="n">terminal1</span><span class="p">,</span> <span class="n">terminal2</span> <span class="ow">in</span> <span class="n">face_to_face</span><span class="p">:</span>
            <span class="n">p1</span> <span class="o">=</span> <span class="n">terminal1</span><span class="o">.</span><span class="n">route_pt</span>
            <span class="n">p2</span> <span class="o">=</span> <span class="n">terminal2</span><span class="o">.</span><span class="n">route_pt</span>
            <span class="n">draw_seg</span><span class="p">(</span>
                <span class="n">Segment</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">),</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="o">=</span><span class="n">thickness</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">0</span>
            <span class="p">)</span>


<span class="k">class</span> <span class="nc">GlobalRoute</span><span class="p">(</span><span class="nb">list</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;A list containing GlobalWires that form an entire routing of a net.</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): The net associated with the wire.</span>
<span class="sd">            *args: Positional args passed to list superclass __init__().</span>
<span class="sd">            **kwargs: Keyword args passed to list superclass __init__().</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">cvt_faces_to_terminals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Convert GlobalWires in route to switchbox terminal-to-terminal route.&quot;&quot;&quot;</span>
        <span class="k">for</span> <span class="n">wire</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="n">wire</span><span class="o">.</span><span class="n">cvt_faces_to_terminals</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">thickness</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw the GlobalWires of this route in the drawing area.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (PyGame screen): Screen object for PyGame drawing.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            font (PyGame font): Font for rendering text.</span>
<span class="sd">            color (list): Three-element list of RGB integers with range [0, 255].</span>
<span class="sd">            thickness (int): Thickness of drawn wire in pixels.</span>
<span class="sd">            dot_radius (int): Radius of drawn terminal in pixels.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>

<span class="sd">        Returns:</span>
<span class="sd">            None.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">wire</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="n">wire</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="p">,</span> <span class="n">dot_radius</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">GlobalTrack</span><span class="p">(</span><span class="nb">list</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="n">HORZ</span><span class="p">,</span> <span class="n">coord</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">idx</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;A horizontal/vertical track holding zero or more faces all having the same Y/X coordinate.</span>

<span class="sd">        These global tracks are made by extending the edges of part bounding boxes to</span>
<span class="sd">        form a non-regular grid of rectangular switchboxes. These tracks are *NOT* the same</span>
<span class="sd">        as the tracks used within a switchbox for the detailed routing phase.</span>

<span class="sd">        Args:</span>
<span class="sd">            orientation (Orientation): Orientation of track (horizontal or vertical).</span>
<span class="sd">            coord (int): Coordinate of track on axis orthogonal to track direction.</span>
<span class="sd">            idx (int): Index of track into a list of X or Y coords.</span>
<span class="sd">            *args: Positional args passed to list superclass __init__().</span>
<span class="sd">            **kwargs: Keyword args passed to list superclass __init__().</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">orientation</span> <span class="o">=</span> <span class="n">orientation</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">=</span> <span class="n">coord</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">idx</span> <span class="o">=</span> <span class="n">idx</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

        <span class="c1"># This stores the orthogonal tracks that intersect this one.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">splits</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">==</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">!=</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__gt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">&gt;</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__ge__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">&gt;=</span> <span class="n">track</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="fm">__sub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Subtract coords of two tracks.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">coord</span> <span class="o">-</span> <span class="n">other</span><span class="o">.</span><span class="n">coord</span>

    <span class="k">def</span> <span class="nf">extend_faces</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orthogonal_tracks</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Extend the faces in a track.</span>

<span class="sd">        This is part of forming the irregular grid of switchboxes.</span>

<span class="sd">        Args:</span>
<span class="sd">            orthogonal_tracks (list): List of tracks orthogonal to this one (L/R vs. H/V).</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[:]:</span>
            <span class="n">face</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">orthogonal_tracks</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;This method lets a track be inserted into a set of splits.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">idx</span>

    <span class="k">def</span> <span class="nf">add_split</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orthogonal_track</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Store the orthogonal track that intersects this one.&quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">splits</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">orthogonal_track</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">add_face</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">face</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add a face to a track.</span>

<span class="sd">        Args:</span>
<span class="sd">            face (Face): Face to be added to track.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">face</span><span class="p">)</span>

        <span class="c1"># The orthogonal tracks that bound the added face will split this track.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">add_split</span><span class="p">(</span><span class="n">face</span><span class="o">.</span><span class="n">beg</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">add_split</span><span class="p">(</span><span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">split_faces</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Split track faces by any intersecting orthogonal tracks.&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">split</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">splits</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[:]:</span>
                <span class="c1"># Apply the split track to the face. The face will only be split</span>
                <span class="c1"># if the split track intersects it. Any split faces will be added</span>
                <span class="c1"># to the track this face is on.</span>
                <span class="n">face</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">split</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">remove_duplicate_faces</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove faces from the track having the same endpoints.&quot;&quot;&quot;</span>

        <span class="c1"># Create lists of faces having the same endpoints.</span>
        <span class="n">dup_faces_dict</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="n">key</span> <span class="o">=</span> <span class="p">(</span><span class="n">face</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="p">)</span>
            <span class="n">dup_faces_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">face</span><span class="p">)</span>

        <span class="c1"># Remove all but the first face from each list.</span>
        <span class="k">for</span> <span class="n">dup_faces</span> <span class="ow">in</span> <span class="n">dup_faces_dict</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="n">retained_face</span> <span class="o">=</span> <span class="n">dup_faces</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">for</span> <span class="n">dup_face</span> <span class="ow">in</span> <span class="n">dup_faces</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
                <span class="c1"># Add info from duplicate face to the retained face.</span>
                <span class="n">retained_face</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">dup_face</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">dup_face</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">remove_terminal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">terminal</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove a terminal from any non-part Faces in the track.&quot;&quot;&quot;</span>

        <span class="n">coord</span> <span class="o">=</span> <span class="n">terminal</span><span class="o">.</span><span class="n">coord</span>
        <span class="c1"># Look for the terminal in all non-part faces on the track.</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">face</span><span class="o">.</span><span class="n">terminals</span><span class="p">[:]:</span>
                    <span class="k">if</span> <span class="n">term</span><span class="o">.</span><span class="n">coord</span> <span class="o">==</span> <span class="n">coord</span><span class="p">:</span>
                        <span class="n">face</span><span class="o">.</span><span class="n">terminals</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">add_adjacencies</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add adjacent switchbox faces to each face in a track.&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">top_face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="n">top_face</span><span class="o">.</span><span class="n">add_adjacencies</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">audit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Raise exception if track is malformed.&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">first_face</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
            <span class="n">first_face</span><span class="o">.</span><span class="n">audit</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">second_face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:]:</span>
                <span class="k">if</span> <span class="n">first_face</span><span class="o">.</span><span class="n">has_overlap</span><span class="p">(</span><span class="n">second_face</span><span class="p">):</span>
                    <span class="k">raise</span> <span class="ne">AssertionError</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw the Faces in a track.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (_type_): _descriptio            scr (PyGame screen): Screen object for PyGame drawing.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            font (PyGame font): Font for rendering text.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
            <span class="n">face</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Target</span><span class="p">:</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">net</span><span class="p">,</span> <span class="n">row</span><span class="p">,</span> <span class="n">col</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;A point on a switchbox face that switchbox router has not yet reached.</span>

<span class="sd">        Targets are used to direct the switchbox router towards terminals that</span>
<span class="sd">        need to be connected to nets. So wiring will be nudged up/down to</span>
<span class="sd">        get closer to terminals along the upper/lower faces. Wiring will also</span>
<span class="sd">        be nudged toward the track rows where terminals on the right face reside</span>
<span class="sd">        as the router works from the left to the right.</span>

<span class="sd">        Args:</span>
<span class="sd">            net (Net): Target net.</span>
<span class="sd">            row (int): Track row for the target, including top or bottom faces.</span>
<span class="sd">            col (int): Switchbox column for the target.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">row</span> <span class="o">=</span> <span class="n">row</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">col</span> <span class="o">=</span> <span class="n">col</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">net</span> <span class="o">=</span> <span class="n">net</span>

    <span class="k">def</span> <span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Used for ordering Targets in terms of priority.&quot;&quot;&quot;</span>

        <span class="c1"># Targets in the left-most columns are given priority since they will be reached</span>
        <span class="c1"># first as the switchbox router proceeds from left-to-right.</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">col</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">row</span><span class="p">,</span> <span class="nb">id</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">net</span><span class="p">))</span> <span class="o">&lt;</span> <span class="p">(</span>
            <span class="n">other</span><span class="o">.</span><span class="n">col</span><span class="p">,</span>
            <span class="n">other</span><span class="o">.</span><span class="n">row</span><span class="p">,</span>
            <span class="nb">id</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">net</span><span class="p">),</span>
        <span class="p">)</span>


<span class="k">class</span> <span class="nc">SwitchBox</span><span class="p">:</span>
    <span class="c1"># Indices for faces of the switchbox.</span>
    <span class="n">TOP</span><span class="p">,</span> <span class="n">LEFT</span><span class="p">,</span> <span class="n">BOTTOM</span><span class="p">,</span> <span class="n">RIGHT</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">top_face</span><span class="p">,</span> <span class="n">left_face</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">bottom_face</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">right_face</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Routing switchbox.</span>

<span class="sd">        A switchbox is a rectangular region through which wires are routed.</span>
<span class="sd">        It has top, bottom, left and right faces.</span>

<span class="sd">        Args:</span>
<span class="sd">            top_face (Face): The top face of the switchbox (needed to find the other faces).</span>
<span class="sd">            bottom_face (Face): The bottom face. Will be calculated if set to None.</span>
<span class="sd">            left_face (Face): The left face. Will be calculated if set to None.</span>
<span class="sd">            right_face (Face): The right face. Will be calculated if set to None.</span>

<span class="sd">        Raises:</span>
<span class="sd">            NoSwitchBox: Exception raised if the switchbox is an</span>
<span class="sd">                unroutable region inside a part bounding box.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Find the left face in the left track that bounds the top face.</span>
        <span class="k">if</span> <span class="n">left_face</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">left_track</span> <span class="o">=</span> <span class="n">top_face</span><span class="o">.</span><span class="n">beg</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">left_track</span><span class="p">:</span>
                <span class="c1"># The left face will end at the track for the top face.</span>
                <span class="k">if</span> <span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span> <span class="o">==</span> <span class="n">top_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">:</span>
                    <span class="n">left_face</span> <span class="o">=</span> <span class="n">face</span>
                    <span class="k">break</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NoSwitchBox</span><span class="p">(</span><span class="s2">&quot;Unroutable switchbox (left)!&quot;</span><span class="p">)</span>

        <span class="c1"># Find the right face in the right track that bounds the top face.</span>
        <span class="k">if</span> <span class="n">right_face</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">right_track</span> <span class="o">=</span> <span class="n">top_face</span><span class="o">.</span><span class="n">end</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">right_track</span><span class="p">:</span>
                <span class="c1"># The right face will end at the track for the top face.</span>
                <span class="k">if</span> <span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span> <span class="o">==</span> <span class="n">top_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">:</span>
                    <span class="n">right_face</span> <span class="o">=</span> <span class="n">face</span>
                    <span class="k">break</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NoSwitchBox</span><span class="p">(</span><span class="s2">&quot;Unroutable switchbox (right)!&quot;</span><span class="p">)</span>

        <span class="c1"># For a routable switchbox, the left and right faces should each</span>
        <span class="c1"># begin at the same point.</span>
        <span class="k">if</span> <span class="n">left_face</span><span class="o">.</span><span class="n">beg</span> <span class="o">!=</span> <span class="n">right_face</span><span class="o">.</span><span class="n">beg</span><span class="p">:</span>
            <span class="c1"># Inequality only happens when two parts are butted up against each other</span>
            <span class="c1"># to form a non-routable switchbox inside a part bounding box.</span>
            <span class="k">raise</span> <span class="n">NoSwitchBox</span><span class="p">(</span><span class="s2">&quot;Unroutable switchbox (left-right)!&quot;</span><span class="p">)</span>

        <span class="c1"># Find the bottom face in the track where the left/right faces begin.</span>
        <span class="k">if</span> <span class="n">bottom_face</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">bottom_track</span> <span class="o">=</span> <span class="n">left_face</span><span class="o">.</span><span class="n">beg</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">bottom_track</span><span class="p">:</span>
                <span class="c1"># The bottom face should begin/end in the same places as the top face.</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">face</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span>
                    <span class="n">top_face</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span>
                    <span class="n">top_face</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span>
                <span class="p">):</span>
                    <span class="n">bottom_face</span> <span class="o">=</span> <span class="n">face</span>
                    <span class="k">break</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NoSwitchBox</span><span class="p">(</span><span class="s2">&quot;Unroutable switchbox (bottom)!&quot;</span><span class="p">)</span>

        <span class="c1"># If all four sides have a part in common, then the switchbox is inside</span>
        <span class="c1"># a part bbox that wires cannot be routed through.</span>
        <span class="k">if</span> <span class="n">top_face</span><span class="o">.</span><span class="n">part</span> <span class="o">&amp;</span> <span class="n">bottom_face</span><span class="o">.</span><span class="n">part</span> <span class="o">&amp;</span> <span class="n">left_face</span><span class="o">.</span><span class="n">part</span> <span class="o">&amp;</span> <span class="n">right_face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">NoSwitchBox</span><span class="p">(</span><span class="s2">&quot;Unroutable switchbox (part)!&quot;</span><span class="p">)</span>

        <span class="c1"># Store the faces.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span> <span class="o">=</span> <span class="n">top_face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span> <span class="o">=</span> <span class="n">bottom_face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span> <span class="o">=</span> <span class="n">left_face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span> <span class="o">=</span> <span class="n">right_face</span>

        <span class="c1"># Each face records which switchboxes it belongs to.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>

        <span class="k">def</span> <span class="nf">find_terminal_net</span><span class="p">(</span><span class="n">terminals</span><span class="p">,</span> <span class="n">terminal_coords</span><span class="p">,</span> <span class="n">coord</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return the net attached to a terminal at the given coordinate.</span>

<span class="sd">            Args:</span>
<span class="sd">                terminals (list): List of Terminals to search.</span>
<span class="sd">                terminal_coords (list): List of integer coordinates for Terminals.</span>
<span class="sd">                coord (int): Terminal coordinate to search for.</span>

<span class="sd">            Returns:</span>
<span class="sd">                Net/None: Net at given coordinate or None if no net exists.</span>
<span class="sd">            &quot;&quot;&quot;</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">terminals</span><span class="p">[</span><span class="n">terminal_coords</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">coord</span><span class="p">)]</span><span class="o">.</span><span class="n">net</span>
            <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                <span class="k">return</span> <span class="kc">None</span>

        <span class="c1"># Find the coordinates of all the horizontal routing tracks</span>
        <span class="n">left_coords</span> <span class="o">=</span> <span class="p">[</span><span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">]</span>
        <span class="n">right_coords</span> <span class="o">=</span> <span class="p">[</span><span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">]</span>
        <span class="n">tb_coords</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">]</span>
        <span class="c1"># Remove duplicate coords.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">left_coords</span> <span class="o">+</span> <span class="n">right_coords</span> <span class="o">+</span> <span class="n">tb_coords</span><span class="p">))</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
            <span class="c1"># This is a weird case. If the switchbox channel is too narrow to hold</span>
            <span class="c1"># a routing track in the middle, then place two pseudo-tracks along the</span>
            <span class="c1"># top and bottom faces to allow routing to proceed. The routed wires will</span>
            <span class="c1"># end up in the top or bottom faces, but maybe that&#39;s OK.</span>
            <span class="c1"># FIXME: Should this be extending with tb_coords?</span>
            <span class="c1"># FIXME: Should we always extend with tb_coords?</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">)</span>

        <span class="c1"># Sort horiz. track coords from bottom to top.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">)</span>

        <span class="c1"># Create a list of nets for each of the left/right faces.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">find_terminal_net</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">,</span> <span class="n">left_coords</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">coord</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span>
        <span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">find_terminal_net</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">,</span> <span class="n">right_coords</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">coord</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span>
        <span class="p">]</span>

        <span class="c1"># Find the coordinates of all the vertical columns and then create</span>
        <span class="c1"># a list of nets for each of the top/bottom faces.</span>
        <span class="n">top_coords</span> <span class="o">=</span> <span class="p">[</span><span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">]</span>
        <span class="n">bottom_coords</span> <span class="o">=</span> <span class="p">[</span><span class="n">terminal</span><span class="o">.</span><span class="n">coord</span> <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">]</span>
        <span class="n">lr_coords</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">top_coords</span> <span class="o">+</span> <span class="n">bottom_coords</span> <span class="o">+</span> <span class="n">lr_coords</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">find_terminal_net</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">,</span> <span class="n">top_coords</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">coord</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span>
        <span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">find_terminal_net</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">terminals</span><span class="p">,</span> <span class="n">bottom_coords</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">coord</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span>
        <span class="p">]</span>

        <span class="c1"># Remove any nets that only have a single terminal in the switchbox.</span>
        <span class="n">all_nets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span>
        <span class="n">net_counts</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">(</span><span class="n">all_nets</span><span class="p">)</span>
        <span class="n">single_terminal_nets</span> <span class="o">=</span> <span class="p">[</span><span class="n">net</span> <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">count</span> <span class="ow">in</span> <span class="n">net_counts</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">count</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">single_terminal_nets</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">side_nets</span> <span class="ow">in</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">,</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">,</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">,</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">,</span>
            <span class="p">):</span>
                <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">net</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">side_nets</span><span class="p">):</span>
                    <span class="k">if</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">single_terminal_nets</span><span class="p">:</span>
                        <span class="n">side_nets</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># Handle special case when a terminal is right on the corner of the switchbox.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">move_corner_nets</span><span class="p">()</span>

        <span class="c1"># Storage for detailed routing.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">segments</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">audit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Raise exception if switchbox is malformed.&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">face_list</span><span class="p">:</span>
            <span class="n">face</span><span class="o">.</span><span class="n">audit</span><span class="p">()</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">HORZ</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">HORZ</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">VERT</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="n">VERT</span>
        <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">)</span>
        <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">face_list</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of switchbox faces in CCW order, starting from top face.&quot;&quot;&quot;</span>
        <span class="n">flst</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">4</span>
        <span class="n">flst</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">TOP</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span>
        <span class="n">flst</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">LEFT</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span>
        <span class="n">flst</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">BOTTOM</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span>
        <span class="n">flst</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">RIGHT</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span>
        <span class="k">return</span> <span class="n">flst</span>

    <span class="k">def</span> <span class="nf">move_corner_nets</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Move any nets at the edges of the left/right faces</span>
<span class="sd">        (i.e., the corners) to the edges of the top/bottom faces.</span>
<span class="sd">        This will allow these nets to be routed within the switchbox columns</span>
<span class="sd">        as the routing proceeds from left to right.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="c1"># Move bottommost net on left face to leftmost net on bottom face.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
            <span class="c1"># Move topmost net on left face to leftmost net on top face.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="c1"># Move bottommost net on right face to rightmost net on bottom face.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
            <span class="c1"># Move topmost net on right face to rightmost net on top face.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

    <span class="k">def</span> <span class="nf">flip_xy</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Flip X-Y of switchbox to route from top-to-bottom instead of left-to-right.&quot;&quot;&quot;</span>

        <span class="c1"># Flip coords of tracks and columns.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span>

        <span class="c1"># Flip top/right and bottom/left nets.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span>

        <span class="c1"># Flip top/right and bottom/left faces.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span>

        <span class="c1"># Move any corner nets from the new left/right faces to the new top/bottom faces.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">move_corner_nets</span><span class="p">()</span>

        <span class="c1"># Flip X/Y coords of any routed segments.</span>
        <span class="k">for</span> <span class="n">segments</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">segments</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                <span class="n">seg</span><span class="o">.</span><span class="n">flip_xy</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">coalesce</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">switchboxes</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Group switchboxes around a seed switchbox into a larger switchbox.</span>

<span class="sd">        Args:</span>
<span class="sd">            switchboxes (list): List of seed switchboxes that have not yet been coalesced into a larger switchbox.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A coalesced switchbox or None if the seed was no longer available for coalescing.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Abort if the switchbox is no longer a potential seed (it was already merged into a previous switchbox).</span>
        <span class="k">if</span> <span class="bp">self</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">switchboxes</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>

        <span class="c1"># Remove the switchbox from the list of seeds.</span>
        <span class="n">switchboxes</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>

        <span class="c1"># List the switchboxes along the top, left, bottom and right borders of the coalesced switchbox.</span>
        <span class="n">box_lists</span> <span class="o">=</span> <span class="p">[[</span><span class="bp">self</span><span class="p">],</span> <span class="p">[</span><span class="bp">self</span><span class="p">],</span> <span class="p">[</span><span class="bp">self</span><span class="p">],</span> <span class="p">[</span><span class="bp">self</span><span class="p">]]</span>

        <span class="c1"># Iteratively search to the top, left, bottom, and right for switchboxes to add.</span>
        <span class="n">active_directions</span> <span class="o">=</span> <span class="p">{</span><span class="bp">self</span><span class="o">.</span><span class="n">TOP</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">LEFT</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">BOTTOM</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">RIGHT</span><span class="p">}</span>
        <span class="k">while</span> <span class="n">active_directions</span><span class="p">:</span>
            <span class="c1"># Grow in the shortest dimension so the coalesced switchbox stays &quot;squarish&quot;.</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">box_list</span> <span class="ow">in</span> <span class="n">box_lists</span><span class="p">:</span>
                <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">box_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">bbox</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">bbox</span><span class="o">.</span><span class="n">w</span> <span class="o">==</span> <span class="n">bbox</span><span class="o">.</span><span class="n">h</span><span class="p">:</span>
                <span class="c1"># Already square, so grow in any direction.</span>
                <span class="n">growth_directions</span> <span class="o">=</span> <span class="p">{</span><span class="bp">self</span><span class="o">.</span><span class="n">TOP</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">LEFT</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">BOTTOM</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">RIGHT</span><span class="p">}</span>
            <span class="k">elif</span> <span class="n">bbox</span><span class="o">.</span><span class="n">w</span> <span class="o">&lt;</span> <span class="n">bbox</span><span class="o">.</span><span class="n">h</span><span class="p">:</span>
                <span class="c1"># Taller than wide, so grow left or right.</span>
                <span class="n">growth_directions</span> <span class="o">=</span> <span class="p">{</span><span class="bp">self</span><span class="o">.</span><span class="n">LEFT</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">RIGHT</span><span class="p">}</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># Wider than tall, so grow up or down.</span>
                <span class="n">growth_directions</span> <span class="o">=</span> <span class="p">{</span><span class="bp">self</span><span class="o">.</span><span class="n">TOP</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">BOTTOM</span><span class="p">}</span>

            <span class="c1"># Only keep growth directions that are still active.</span>
            <span class="n">growth_directions</span> <span class="o">=</span> <span class="n">growth_directions</span> <span class="o">&amp;</span> <span class="n">active_directions</span>

            <span class="c1"># If there is no active growth direction, then stop the growth iterations.</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">growth_directions</span><span class="p">:</span>
                <span class="k">break</span>

            <span class="c1"># Take a random choice of the active growth directions.</span>
            <span class="n">direction</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">growth_directions</span><span class="p">))</span>

            <span class="c1"># Check the switchboxes along the growth side to see if further expansion is possible.</span>
            <span class="n">box_list</span> <span class="o">=</span> <span class="n">box_lists</span><span class="p">[</span><span class="n">direction</span><span class="p">]</span>
            <span class="k">for</span> <span class="n">box</span> <span class="ow">in</span> <span class="n">box_list</span><span class="p">:</span>
                <span class="c1"># Get the face of the box from which growth will occur.</span>
                <span class="n">box_face</span> <span class="o">=</span> <span class="n">box</span><span class="o">.</span><span class="n">face_list</span><span class="p">[</span><span class="n">direction</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">box_face</span><span class="o">.</span><span class="n">part</span><span class="p">:</span>
                    <span class="c1"># This box butts up against a part, so expansion in this direction is blocked.</span>
                    <span class="n">active_directions</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">direction</span><span class="p">)</span>
                    <span class="k">break</span>
                <span class="c1"># Get the box which will be added if expansion occurs.</span>
                <span class="c1"># Every face borders two switchboxes, so the adjacent box is the other one.</span>
                <span class="n">adj_box</span> <span class="o">=</span> <span class="p">(</span><span class="n">box_face</span><span class="o">.</span><span class="n">switchboxes</span> <span class="o">-</span> <span class="p">{</span><span class="n">box</span><span class="p">})</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
                <span class="k">if</span> <span class="n">adj_box</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">switchboxes</span><span class="p">:</span>
                    <span class="c1"># This box cannot be added, so expansion in this direction is blocked.</span>
                    <span class="n">active_directions</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">direction</span><span class="p">)</span>
                    <span class="k">break</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># All the switchboxes along the growth side are available for expansion,</span>
                <span class="c1"># so replace the current boxes in the growth side with these new ones.</span>
                <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">box</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">box_list</span><span class="p">[:]):</span>
                    <span class="c1"># Get the adjacent box for the current box on the growth side.</span>
                    <span class="n">box_face</span> <span class="o">=</span> <span class="n">box</span><span class="o">.</span><span class="n">face_list</span><span class="p">[</span><span class="n">direction</span><span class="p">]</span>
                    <span class="n">adj_box</span> <span class="o">=</span> <span class="p">(</span><span class="n">box_face</span><span class="o">.</span><span class="n">switchboxes</span> <span class="o">-</span> <span class="p">{</span><span class="n">box</span><span class="p">})</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
                    <span class="c1"># Replace the current box with the new box from the expansion.</span>
                    <span class="n">box_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">adj_box</span>
                    <span class="c1"># Remove the newly added box from the list of available boxes for growth.</span>
                    <span class="n">switchboxes</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">adj_box</span><span class="p">)</span>

                <span class="c1"># Add the first box on the growth side to the end of the list of boxes on the</span>
                <span class="c1"># preceding direction: (top,left,bottom,right) if current direction is (left,bottom,right,top).</span>
                <span class="n">box_lists</span><span class="p">[</span><span class="n">direction</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">box_list</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

                <span class="c1"># Add the last box on the growth side to the start of the list of boxes on the</span>
                <span class="c1"># next direction: (bottom,right,top,left) if current direction is (left,bottom,right,top).</span>
                <span class="n">box_lists</span><span class="p">[(</span><span class="n">direction</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="mi">4</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">box_list</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>

        <span class="c1"># Create new faces that bound the coalesced group of switchboxes.</span>
        <span class="n">total_faces</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span>
        <span class="n">directions</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">TOP</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">LEFT</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">BOTTOM</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">RIGHT</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">direction</span><span class="p">,</span> <span class="n">box_list</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">directions</span><span class="p">,</span> <span class="n">box_lists</span><span class="p">):</span>
            <span class="c1"># Create a face that spans all the faces of the boxes along one side.</span>
            <span class="n">face_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">box</span><span class="o">.</span><span class="n">face_list</span><span class="p">[</span><span class="n">direction</span><span class="p">]</span> <span class="k">for</span> <span class="n">box</span> <span class="ow">in</span> <span class="n">box_list</span><span class="p">]</span>
            <span class="n">beg</span> <span class="o">=</span> <span class="nb">min</span><span class="p">([</span><span class="n">face</span><span class="o">.</span><span class="n">beg</span> <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">face_list</span><span class="p">])</span>
            <span class="n">end</span> <span class="o">=</span> <span class="nb">max</span><span class="p">([</span><span class="n">face</span><span class="o">.</span><span class="n">end</span> <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">face_list</span><span class="p">])</span>
            <span class="n">total_face</span> <span class="o">=</span> <span class="n">Face</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">face_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">track</span><span class="p">,</span> <span class="n">beg</span><span class="p">,</span> <span class="n">end</span><span class="p">)</span>

            <span class="c1"># Add terminals from the box faces along one side.</span>
            <span class="n">total_face</span><span class="o">.</span><span class="n">create_nonpin_terminals</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">face_list</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">face</span><span class="o">.</span><span class="n">terminals</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">terminal</span><span class="o">.</span><span class="n">net</span><span class="p">:</span>
                        <span class="n">total_face</span><span class="o">.</span><span class="n">add_terminal</span><span class="p">(</span><span class="n">terminal</span><span class="o">.</span><span class="n">net</span><span class="p">,</span> <span class="n">terminal</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>

            <span class="c1"># Set the routing capacity of the new face.</span>
            <span class="n">total_face</span><span class="o">.</span><span class="n">set_capacity</span><span class="p">()</span>

            <span class="c1"># Store the new face for this side.</span>
            <span class="n">total_faces</span><span class="p">[</span><span class="n">direction</span><span class="p">]</span> <span class="o">=</span> <span class="n">total_face</span>

        <span class="c1"># Return the coalesced switchbox created from the new faces.</span>
        <span class="k">return</span> <span class="n">SwitchBox</span><span class="p">(</span><span class="o">*</span><span class="n">total_faces</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">trim_repeated_terminals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Trim terminals on each face.&quot;&quot;&quot;</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">face_list</span><span class="p">:</span>
            <span class="n">face</span><span class="o">.</span><span class="n">trim_repeated_terminals</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">bbox</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return bounding box for a switchbox.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">BBox</span><span class="p">()</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">bbox</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">bbox</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">has_nets</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if switchbox has any terminals on any face with nets attached.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">has_nets</span><span class="p">()</span>
            <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">has_nets</span><span class="p">()</span>
            <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">has_nets</span><span class="p">()</span>
            <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">has_nets</span><span class="p">()</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Route wires between terminals on the switchbox faces.</span>

<span class="sd">        Args:</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>

<span class="sd">        Raises:</span>
<span class="sd">            RoutingFailure: Raised if routing could not be completed.</span>

<span class="sd">        Returns:</span>
<span class="sd">            List of Segments: List of wiring segments for switchbox routes.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_nets</span><span class="p">():</span>
            <span class="c1"># Return what should be an empty dict.</span>
            <span class="k">assert</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">segments</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">segments</span>

        <span class="k">def</span> <span class="nf">collect_targets</span><span class="p">(</span><span class="n">top_nets</span><span class="p">,</span> <span class="n">bottom_nets</span><span class="p">,</span> <span class="n">right_nets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Collect target nets along top, bottom, right faces of switchbox.&quot;&quot;&quot;</span>

            <span class="n">min_row</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="n">max_row</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">right_nets</span><span class="p">)</span> <span class="o">-</span> <span class="mi">2</span>
            <span class="n">max_col</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">top_nets</span><span class="p">)</span>
            <span class="n">targets</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># Collect target nets along top and bottom faces of the switchbox.</span>
            <span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="n">b_net</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">top_nets</span><span class="p">,</span> <span class="n">bottom_nets</span><span class="p">)):</span>
                <span class="k">if</span> <span class="n">t_net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                    <span class="n">targets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Target</span><span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="n">max_row</span><span class="p">,</span> <span class="n">col</span><span class="p">))</span>
                <span class="k">if</span> <span class="n">b_net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                    <span class="n">targets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Target</span><span class="p">(</span><span class="n">b_net</span><span class="p">,</span> <span class="n">min_row</span><span class="p">,</span> <span class="n">col</span><span class="p">))</span>

            <span class="c1"># Collect target nets on the right face of the switchbox.</span>
            <span class="k">for</span> <span class="n">row</span><span class="p">,</span> <span class="n">r_net</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">right_nets</span><span class="p">):</span>
                <span class="k">if</span> <span class="n">r_net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                    <span class="n">targets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Target</span><span class="p">(</span><span class="n">r_net</span><span class="p">,</span> <span class="n">row</span><span class="p">,</span> <span class="n">max_col</span><span class="p">))</span>

            <span class="c1"># Sort the targets by increasing column order so targets closer to</span>
            <span class="c1"># the left-to-right routing have priority.</span>
            <span class="n">targets</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>

            <span class="k">return</span> <span class="n">targets</span>

        <span class="k">def</span> <span class="nf">connect_top_btm</span><span class="p">(</span><span class="n">track_nets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Connect nets from top/bottom terminals in a column to nets in horizontal tracks of the switchbox.&quot;&quot;&quot;</span>

            <span class="k">def</span> <span class="nf">find_connection</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">tracks</span><span class="p">,</span> <span class="n">direction</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                Searches for the closest track with the same net followed by the</span>
<span class="sd">                closest empty track. The indices of these tracks are returned.</span>
<span class="sd">                If the net cannot be connected to any track, return [].</span>
<span class="sd">                If the net given to connect is None, then return a list of [None].</span>

<span class="sd">                Args:</span>
<span class="sd">                    net (Net): Net to be connected.</span>
<span class="sd">                    tracks (list): Nets on tracks</span>
<span class="sd">                    direction (int): Search direction for connection (-1: down, +1:up).</span>

<span class="sd">                Returns:</span>
<span class="sd">                    list: Indices of tracks where the net can connect.</span>
<span class="sd">                &quot;&quot;&quot;</span>

                <span class="k">if</span> <span class="n">net</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">direction</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="c1"># Searching down so reverse tracks.</span>
                        <span class="n">tracks</span> <span class="o">=</span> <span class="n">tracks</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

                    <span class="n">connections</span> <span class="o">=</span> <span class="p">[]</span>

                    <span class="k">try</span><span class="p">:</span>
                        <span class="c1"># Find closest track with the given net.</span>
                        <span class="n">connections</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tracks</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">net</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
                    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                        <span class="k">pass</span>

                    <span class="k">try</span><span class="p">:</span>
                        <span class="c1"># Find closest empty track.</span>
                        <span class="n">connections</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tracks</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
                    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                        <span class="k">pass</span>

                    <span class="k">if</span> <span class="n">direction</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="c1"># Reverse track indices if searching down.</span>
                        <span class="n">l</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">tracks</span><span class="p">)</span>
                        <span class="n">connections</span> <span class="o">=</span> <span class="p">[</span><span class="n">l</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">cnct</span> <span class="k">for</span> <span class="n">cnct</span> <span class="ow">in</span> <span class="n">connections</span><span class="p">]</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># No net so return no connections.</span>
                    <span class="n">connections</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span>

                <span class="k">return</span> <span class="n">connections</span>

            <span class="c1"># Stores net intervals connecting top/bottom nets to horizontal tracks.</span>
            <span class="n">column_intvls</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># Top/bottom nets for this switchbox column. Horizontal track nets are</span>
            <span class="c1"># at indexes 1..-2.</span>
            <span class="n">b_net</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">t_net</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

            <span class="k">if</span> <span class="n">t_net</span> <span class="ow">and</span> <span class="p">(</span><span class="n">t_net</span> <span class="ow">is</span> <span class="n">b_net</span><span class="p">):</span>
                <span class="c1"># If top &amp; bottom nets are the same, just create a single net interval</span>
                <span class="c1"># connecting them and that&#39;s it.</span>
                <span class="n">column_intvls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NetInterval</span><span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span>
                <span class="k">return</span> <span class="n">column_intvls</span>

            <span class="c1"># Find which tracks the top/bottom nets can connect to.</span>
            <span class="n">t_cncts</span> <span class="o">=</span> <span class="n">find_connection</span><span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="n">track_nets</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
            <span class="n">b_cncts</span> <span class="o">=</span> <span class="n">find_connection</span><span class="p">(</span><span class="n">b_net</span><span class="p">,</span> <span class="n">track_nets</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

            <span class="c1"># Create all possible pairs of top/bottom connections.</span>
            <span class="n">tb_cncts</span> <span class="o">=</span> <span class="p">[(</span><span class="n">t</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">t_cncts</span> <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_cncts</span><span class="p">]</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">tb_cncts</span><span class="p">:</span>
                <span class="c1"># No possible connections for top and/or bottom.</span>
                <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;allow_routing_failure&quot;</span><span class="p">):</span>
                    <span class="k">return</span> <span class="n">column_intvls</span>  <span class="c1"># Return empty column.</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="n">SwitchboxRoutingFailure</span>

            <span class="c1"># Test each possible pair of connections to find one that is free of interference.</span>
            <span class="k">for</span> <span class="n">t_cnct</span><span class="p">,</span> <span class="n">b_cnct</span> <span class="ow">in</span> <span class="n">tb_cncts</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">t_cnct</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">b_cnct</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                    <span class="c1"># No possible interference if at least one connection is None.</span>
                    <span class="k">break</span>
                <span class="k">if</span> <span class="n">t_cnct</span> <span class="o">&gt;</span> <span class="n">b_cnct</span><span class="p">:</span>
                    <span class="c1"># Top &amp; bottom connections don&#39;t interfere.</span>
                    <span class="k">break</span>
                <span class="k">if</span> <span class="n">t_cnct</span> <span class="o">==</span> <span class="n">b_cnct</span> <span class="ow">and</span> <span class="n">t_net</span> <span class="ow">is</span> <span class="n">b_net</span><span class="p">:</span>
                    <span class="c1"># Top &amp; bottom connect to the same track but they&#39;re the same net so that&#39;s OK.</span>
                    <span class="k">break</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;allow_routing_failure&quot;</span><span class="p">):</span>
                    <span class="k">return</span> <span class="n">column_intvls</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="n">SwitchboxRoutingFailure</span>

            <span class="k">if</span> <span class="n">t_cnct</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># Connection from track to terminal on top of switchbox.</span>
                <span class="n">column_intvls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NetInterval</span><span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="n">t_cnct</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span>
            <span class="k">if</span> <span class="n">b_cnct</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># Connection from terminal on bottom of switchbox to track.</span>
                <span class="n">column_intvls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NetInterval</span><span class="p">(</span><span class="n">b_net</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">b_cnct</span><span class="p">))</span>

            <span class="c1"># Return connection segments.</span>
            <span class="k">return</span> <span class="n">column_intvls</span>

        <span class="k">def</span> <span class="nf">prune_targets</span><span class="p">(</span><span class="n">targets</span><span class="p">,</span> <span class="n">current_col</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Remove targets in columns to the left of the current left-to-right routing column&quot;&quot;&quot;</span>
            <span class="k">return</span> <span class="p">[</span><span class="n">target</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">targets</span> <span class="k">if</span> <span class="n">target</span><span class="o">.</span><span class="n">col</span> <span class="o">&gt;</span> <span class="n">current_col</span><span class="p">]</span>

        <span class="k">def</span> <span class="nf">insert_column_nets</span><span class="p">(</span><span class="n">track_nets</span><span class="p">,</span> <span class="n">column_intvls</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return the active nets with the added nets of the column&#39;s vertical intervals.&quot;&quot;&quot;</span>

            <span class="n">nets</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[:]</span>
            <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column_intvls</span><span class="p">:</span>
                <span class="n">nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">]</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">net</span>
                <span class="n">nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">end</span><span class="p">]</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">net</span>
            <span class="k">return</span> <span class="n">nets</span>

        <span class="k">def</span> <span class="nf">net_search</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">track_nets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Search for the closest points for the net before and after the start point.&quot;&quot;&quot;</span>

            <span class="c1"># illegal offset past the end of the list of track nets.</span>
            <span class="n">large_offset</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Find closest occurrence of net going up.</span>
                <span class="n">up</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="n">start</span><span class="p">:]</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                <span class="c1"># Net not found, so use out-of-bounds index.</span>
                <span class="n">up</span> <span class="o">=</span> <span class="n">large_offset</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Find closest occurrence of net going down.</span>
                <span class="n">down</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="n">start</span><span class="p">::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                <span class="c1"># Net not found, so use out-of-bounds index.</span>
                <span class="n">down</span> <span class="o">=</span> <span class="n">large_offset</span>

            <span class="k">if</span> <span class="n">up</span> <span class="o">&lt;=</span> <span class="n">down</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">up</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">return</span> <span class="o">-</span><span class="n">down</span>

        <span class="k">def</span> <span class="nf">insert_target_nets</span><span class="p">(</span><span class="n">track_nets</span><span class="p">,</span> <span class="n">targets</span><span class="p">,</span> <span class="n">right_nets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return copy of active track nets with additional prioritized targets from the top, bottom, right faces.&quot;&quot;&quot;</span>

            <span class="c1"># Allocate storage for potential target nets to be added to the list of active track nets.</span>
            <span class="n">placed_target_nets</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span>

            <span class="c1"># Get a list of nets on the right face that are being actively routed right now</span>
            <span class="c1"># so we can steer the routing as it proceeds rightward.</span>
            <span class="n">active_right_nets</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">net</span> <span class="k">if</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">track_nets</span> <span class="k">else</span> <span class="kc">None</span> <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">right_nets</span>
            <span class="p">]</span>

            <span class="c1"># Strip-off the top/bottom rows where terminals are and routing doesn&#39;t go.</span>
            <span class="n">search_nets</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

            <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">targets</span><span class="p">:</span>
                <span class="n">target_net</span><span class="p">,</span> <span class="n">target_row</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="n">net</span><span class="p">,</span> <span class="n">target</span><span class="o">.</span><span class="n">row</span>

                <span class="c1"># Skip target nets that aren&#39;t currently active or have already been</span>
                <span class="c1"># placed (prevents multiple insertions of the same target net).</span>
                <span class="c1"># Also ignore targets on the far right face until the last step.</span>
                <span class="k">if</span> <span class="p">(</span>
                    <span class="n">target_net</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">track_nets</span>  <span class="c1"># TODO: Use search_nets???</span>
                    <span class="ow">or</span> <span class="n">target_net</span> <span class="ow">in</span> <span class="n">placed_target_nets</span>
                    <span class="ow">or</span> <span class="n">target_net</span> <span class="ow">in</span> <span class="n">active_right_nets</span>
                <span class="p">):</span>
                    <span class="k">continue</span>

                <span class="c1"># Assign the target net to the closest row to the target row that is either</span>
                <span class="c1"># empty or has the same net.</span>
                <span class="n">net_row_offset</span> <span class="o">=</span> <span class="n">net_search</span><span class="p">(</span><span class="n">target_net</span><span class="p">,</span> <span class="n">target_row</span><span class="p">,</span> <span class="n">search_nets</span><span class="p">)</span>
                <span class="n">empty_row_offset</span> <span class="o">=</span> <span class="n">net_search</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">target_row</span><span class="p">,</span> <span class="n">search_nets</span><span class="p">)</span>
                <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">net_row_offset</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">empty_row_offset</span><span class="p">):</span>
                    <span class="n">row_offset</span> <span class="o">=</span> <span class="n">net_row_offset</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">row_offset</span> <span class="o">=</span> <span class="n">empty_row_offset</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="n">placed_target_nets</span><span class="p">[</span><span class="n">target_row</span> <span class="o">+</span> <span class="n">row_offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">target_net</span>
                    <span class="n">search_nets</span><span class="p">[</span><span class="n">target_row</span> <span class="o">+</span> <span class="n">row_offset</span><span class="p">]</span> <span class="o">=</span> <span class="n">target_net</span>
                <span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
                    <span class="c1"># There was no place for this target net</span>
                    <span class="k">pass</span>

            <span class="k">return</span> <span class="p">[</span>
                <span class="n">active_net</span> <span class="ow">or</span> <span class="n">target_net</span> <span class="ow">or</span> <span class="n">right_net</span>
                <span class="c1"># active_net or right_net or target_net</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">active_net</span><span class="p">,</span> <span class="n">right_net</span><span class="p">,</span> <span class="n">target_net</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span>
                    <span class="n">track_nets</span><span class="p">,</span> <span class="n">active_right_nets</span><span class="p">,</span> <span class="n">placed_target_nets</span>
                <span class="p">)</span>
            <span class="p">]</span>

        <span class="k">def</span> <span class="nf">connect_splits</span><span class="p">(</span><span class="n">track_nets</span><span class="p">,</span> <span class="n">column</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Vertically connect nets on multiple tracks.&quot;&quot;&quot;</span>

            <span class="c1"># Make a copy so the original isn&#39;t disturbed.</span>
            <span class="n">track_nets</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[:]</span>

            <span class="c1"># Find nets that are running on multiple tracks.</span>
            <span class="n">multi_nets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span>
                <span class="n">net</span> <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span> <span class="k">if</span> <span class="n">track_nets</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">net</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span>
            <span class="p">)</span>
            <span class="n">multi_nets</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>  <span class="c1"># Ignore empty tracks.</span>

            <span class="c1"># Find possible intervals for multi-track nets.</span>
            <span class="n">net_intervals</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">multi_nets</span><span class="p">:</span>
                <span class="n">net_trk_idxs</span> <span class="o">=</span> <span class="p">[</span><span class="n">idx</span> <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">nt</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span> <span class="k">if</span> <span class="n">nt</span> <span class="ow">is</span> <span class="n">net</span><span class="p">]</span>
                <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">trk1</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">net_trk_idxs</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="mi">1</span><span class="p">):</span>
                    <span class="k">for</span> <span class="n">trk2</span> <span class="ow">in</span> <span class="n">net_trk_idxs</span><span class="p">[</span><span class="n">index</span><span class="p">:]:</span>
                        <span class="n">net_intervals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NetInterval</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">trk1</span><span class="p">,</span> <span class="n">trk2</span><span class="p">))</span>

            <span class="c1"># Sort interval lengths from smallest to largest.</span>
            <span class="n">net_intervals</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">ni</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">ni</span><span class="p">))</span>
            <span class="c1"># Sort interval lengths from largest to smallest.</span>
            <span class="c1"># net_intervals.sort(key=lambda ni: -len(ni))</span>

            <span class="c1"># Connect tracks for each interval if it doesn&#39;t intersect an</span>
            <span class="c1"># already existing connection.</span>
            <span class="k">for</span> <span class="n">net_interval</span> <span class="ow">in</span> <span class="n">net_intervals</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">col_interval</span> <span class="ow">in</span> <span class="n">column</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">net_interval</span><span class="o">.</span><span class="n">obstructs</span><span class="p">(</span><span class="n">col_interval</span><span class="p">):</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># No conflicts found with existing connections.</span>
                    <span class="n">column</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">net_interval</span><span class="p">)</span>

            <span class="c1"># Get the nets that have vertical wires in the column.</span>
            <span class="n">column_nets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">intvl</span><span class="o">.</span><span class="n">net</span> <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span><span class="p">)</span>

            <span class="c1"># Merge segments of each net in the column.</span>
            <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">column_nets</span><span class="p">:</span>
                <span class="c1"># Extract intervals if the current net has more than one interval.</span>
                <span class="n">intervals</span> <span class="o">=</span> <span class="p">[</span><span class="n">intvl</span> <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span> <span class="k">if</span> <span class="n">intvl</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="n">net</span><span class="p">]</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervals</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="c1"># Skip if there&#39;s only a single interval for this net.</span>
                    <span class="k">continue</span>

                <span class="c1"># Remove the intervals so they can be replaced with joined intervals.</span>
                <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">intervals</span><span class="p">:</span>
                    <span class="n">column</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">intvl</span><span class="p">)</span>

                <span class="c1"># Merge the extracted intervals as much as possible.</span>

                <span class="c1"># Sort intervals by their beginning coordinates.</span>
                <span class="n">intervals</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">intvl</span><span class="p">:</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">)</span>

                <span class="c1"># Try merging consecutive pairs of intervals.</span>
                <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">intervals</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
                    <span class="c1"># Try to merge consecutive intervals.</span>
                    <span class="n">merged_intvl</span> <span class="o">=</span> <span class="n">intervals</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">intervals</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span>
                    <span class="k">if</span> <span class="n">merged_intvl</span><span class="p">:</span>
                        <span class="c1"># Keep only the merged interval and place it so it&#39;s compared to the next one.</span>
                        <span class="n">intervals</span><span class="p">[</span><span class="n">i</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">merged_intvl</span>

                <span class="c1"># Remove the None entries that are inserted when segments get merged.</span>
                <span class="n">intervals</span> <span class="o">=</span> <span class="p">[</span><span class="n">intvl</span> <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">intervals</span> <span class="k">if</span> <span class="n">intvl</span><span class="p">]</span>

                <span class="c1"># Place merged intervals back into column.</span>
                <span class="n">column</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">intervals</span><span class="p">)</span>

            <span class="k">return</span> <span class="n">column</span>

        <span class="k">def</span> <span class="nf">extend_tracks</span><span class="p">(</span><span class="n">track_nets</span><span class="p">,</span> <span class="n">column</span><span class="p">,</span> <span class="n">targets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Extend track nets into the next column.&quot;&quot;&quot;</span>

            <span class="c1"># These are nets to the right of the current column.</span>
            <span class="n">rightward_nets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">target</span><span class="o">.</span><span class="n">net</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">targets</span><span class="p">)</span>

            <span class="c1"># Keep extending nets to next column if they do not intersect intervals in the</span>
            <span class="c1"># current column with the same net.</span>
            <span class="n">flow_thru_nets</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[:]</span>
            <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">trk_idx</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
                    <span class="k">if</span> <span class="n">flow_thru_nets</span><span class="p">[</span><span class="n">trk_idx</span><span class="p">]</span> <span class="ow">is</span> <span class="n">intvl</span><span class="o">.</span><span class="n">net</span><span class="p">:</span>
                        <span class="c1"># Remove net from track since it intersects an interval with the</span>
                        <span class="c1"># same net. The net may be extended from the interval in the next phase,</span>
                        <span class="c1"># or it may terminate here.</span>
                        <span class="n">flow_thru_nets</span><span class="p">[</span><span class="n">trk_idx</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="n">next_track_nets</span> <span class="o">=</span> <span class="n">flow_thru_nets</span><span class="p">[:]</span>

            <span class="c1"># Extend track net if net has multiple column intervals that need further interconnection</span>
            <span class="c1"># or if there are terminals in rightward columns that need connections to this net.</span>
            <span class="n">first_track</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">last_track</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">track_nets</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
            <span class="n">column_nets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">intvl</span><span class="o">.</span><span class="n">net</span> <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span><span class="p">])</span>
            <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">column_nets</span><span class="p">:</span>
                <span class="c1"># Get all the vertical intervals for this net in the current column.</span>
                <span class="n">net_intervals</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">column</span> <span class="k">if</span> <span class="n">i</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="n">net</span><span class="p">]</span>

                <span class="c1"># No need to extend tracks for this net into next column if there aren&#39;t multiple</span>
                <span class="c1"># intervals or further terminals to connect.</span>
                <span class="k">if</span> <span class="n">net</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">rightward_nets</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">net_intervals</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="k">continue</span>

                <span class="c1"># Sort the net&#39;s intervals from bottom of the column to top.</span>
                <span class="n">net_intervals</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">e</span><span class="o">.</span><span class="n">beg</span><span class="p">)</span>

                <span class="c1"># Find the nearest target to the right matching the current net.</span>
                <span class="n">target_row</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">targets</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">target</span><span class="o">.</span><span class="n">net</span> <span class="ow">is</span> <span class="n">net</span><span class="p">:</span>
                        <span class="n">target_row</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="n">row</span>
                        <span class="k">break</span>

                <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">net_intervals</span><span class="p">):</span>
                    <span class="c1"># Sanity check: should never get here if interval goes from top-to-bottom of</span>
                    <span class="c1"># column (hence, only one interval) and there is no further terminal for this</span>
                    <span class="c1"># net to the right.</span>
                    <span class="k">assert</span> <span class="ow">not</span> <span class="p">(</span>
                        <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="o">==</span> <span class="n">first_track</span>
                        <span class="ow">and</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">==</span> <span class="n">last_track</span>
                        <span class="ow">and</span> <span class="ow">not</span> <span class="n">target_row</span>
                    <span class="p">)</span>

                    <span class="k">if</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="o">==</span> <span class="n">first_track</span> <span class="ow">and</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">&lt;</span> <span class="n">last_track</span><span class="p">:</span>
                        <span class="c1"># Interval starts on bottom of column, so extend net in the track where it ends.</span>
                        <span class="k">assert</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span>
                        <span class="k">assert</span> <span class="n">track_nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">end</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
                        <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                        <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                        <span class="k">continue</span>

                    <span class="k">if</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">==</span> <span class="n">last_track</span> <span class="ow">and</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="o">&gt;</span> <span class="n">first_track</span><span class="p">:</span>
                        <span class="c1"># Interval ends on top of column, so extend net in the track where it begins.</span>
                        <span class="k">assert</span> <span class="n">i</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">net_intervals</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
                        <span class="k">assert</span> <span class="n">track_nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
                        <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span>
                        <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                        <span class="k">continue</span>

                    <span class="k">if</span> <span class="n">target_row</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                        <span class="c1"># No target to the right, so we must be trying to connect multiple column intervals for this net.</span>
                        <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                            <span class="c1"># First interval in column so extend from its top-most point.</span>
                            <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                            <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                        <span class="k">elif</span> <span class="n">i</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">net_intervals</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
                            <span class="c1"># Last interval in column so extend from its bottom-most point.</span>
                            <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span>
                            <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="c1"># This interval is between the top and bottom intervals.</span>
                            <span class="n">beg_end</span> <span class="o">=</span> <span class="p">(</span>
                                <span class="nb">bool</span><span class="p">(</span><span class="n">flow_thru_nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">]),</span>
                                <span class="nb">bool</span><span class="p">(</span><span class="n">flow_thru_nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">end</span><span class="p">]),</span>
                            <span class="p">)</span>
                            <span class="k">if</span> <span class="n">beg_end</span> <span class="o">==</span> <span class="p">(</span><span class="kc">True</span><span class="p">,</span> <span class="kc">False</span><span class="p">):</span>
                                <span class="c1"># The net enters this interval at its bottom, so extend from the top (dogleg).</span>
                                <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                                <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                            <span class="k">elif</span> <span class="n">beg_end</span> <span class="o">==</span> <span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="kc">True</span><span class="p">):</span>
                                <span class="c1"># The net enters this interval at its top, so extend from the bottom (dogleg).</span>
                                <span class="n">exit_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span>
                                <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                            <span class="k">else</span><span class="p">:</span>
                                <span class="k">raise</span> <span class="ne">RuntimeError</span>
                        <span class="k">continue</span>

                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># Target to the right, so aim for it.</span>

                        <span class="k">if</span> <span class="n">target_row</span> <span class="o">&gt;</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span><span class="p">:</span>
                            <span class="c1"># target track is above the interval&#39;s end, so bound it to the end.</span>
                            <span class="n">target_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                        <span class="k">elif</span> <span class="n">target_row</span> <span class="o">&lt;</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">:</span>
                            <span class="c1"># target track is below the interval&#39;s start, so bound it to the start.</span>
                            <span class="n">target_row</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span>

                        <span class="c1"># Search for the closest track to the target row that is either open</span>
                        <span class="c1"># or occupied by the same target net.</span>
                        <span class="n">intvl_nets</span> <span class="o">=</span> <span class="n">track_nets</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="p">:</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
                        <span class="n">net_row</span> <span class="o">=</span> <span class="p">(</span>
                            <span class="n">net_search</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">target_row</span> <span class="o">-</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">intvl_nets</span><span class="p">)</span>
                            <span class="o">+</span> <span class="n">target_row</span>
                        <span class="p">)</span>
                        <span class="n">open_row</span> <span class="o">=</span> <span class="p">(</span>
                            <span class="n">net_search</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">target_row</span> <span class="o">-</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">,</span> <span class="n">intvl_nets</span><span class="p">)</span>
                            <span class="o">+</span> <span class="n">target_row</span>
                        <span class="p">)</span>
                        <span class="n">net_dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">net_row</span> <span class="o">-</span> <span class="n">target_row</span><span class="p">)</span>
                        <span class="n">open_dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">open_row</span> <span class="o">-</span> <span class="n">target_row</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">net_dist</span> <span class="o">&lt;=</span> <span class="n">open_dist</span><span class="p">:</span>
                            <span class="n">exit_row</span> <span class="o">=</span> <span class="n">net_row</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="n">exit_row</span> <span class="o">=</span> <span class="n">open_row</span>
                        <span class="k">assert</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="o">&lt;=</span> <span class="n">exit_row</span> <span class="o">&lt;=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                        <span class="n">next_track_nets</span><span class="p">[</span><span class="n">exit_row</span><span class="p">]</span> <span class="o">=</span> <span class="n">net</span>
                        <span class="k">continue</span>

            <span class="k">return</span> <span class="n">next_track_nets</span>

        <span class="k">def</span> <span class="nf">trim_column_intervals</span><span class="p">(</span><span class="n">column</span><span class="p">,</span> <span class="n">track_nets</span><span class="p">,</span> <span class="n">next_track_nets</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Trim stubs from column intervals.&quot;&quot;&quot;</span>

            <span class="c1"># All nets entering and exiting the column.</span>
            <span class="n">trk_nets</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">enumerate</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">track_nets</span><span class="p">,</span> <span class="n">next_track_nets</span><span class="p">)))</span>

            <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span><span class="p">:</span>
                <span class="c1"># Get all the entry/exit track positions having the same net as the interval</span>
                <span class="c1"># and that are within the bounds of the interval.</span>
                <span class="n">net</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">net</span>
                <span class="n">beg</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span>
                <span class="n">end</span> <span class="o">=</span> <span class="n">intvl</span><span class="o">.</span><span class="n">end</span>
                <span class="n">trks</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">nets</span><span class="p">)</span> <span class="ow">in</span> <span class="n">trk_nets</span> <span class="k">if</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">nets</span> <span class="ow">and</span> <span class="n">beg</span> <span class="o">&lt;=</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">end</span><span class="p">]</span>

                <span class="c1"># Chop off any stubs of the interval that extend past where it could</span>
                <span class="c1"># connect to an entry/exit point of its net.</span>
                <span class="n">intvl</span><span class="o">.</span><span class="n">beg</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">trks</span><span class="p">)</span>
                <span class="n">intvl</span><span class="o">.</span><span class="n">end</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">trks</span><span class="p">)</span>

        <span class="c1">########################################</span>
        <span class="c1"># Main switchbox routing loop.</span>
        <span class="c1">########################################</span>

        <span class="c1"># Get target nets as routing proceeds from left-to-right.</span>
        <span class="n">targets</span> <span class="o">=</span> <span class="n">collect_targets</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">)</span>

        <span class="c1"># Store the nets in each column that are in the process of being routed,</span>
        <span class="c1"># starting with the nets in the left-hand face of the switchbox.</span>
        <span class="n">nets_in_column</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">left_nets</span><span class="p">[:]]</span>

        <span class="c1"># Store routing intervals in each column.</span>
        <span class="n">all_column_intvls</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Route left-to-right across the columns connecting the top &amp; bottom nets</span>
        <span class="c1"># on each column to tracks within the switchbox.</span>
        <span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="p">(</span><span class="n">t_net</span><span class="p">,</span> <span class="n">b_net</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_nets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_nets</span><span class="p">)):</span>
            <span class="c1"># Nets in the previous column become the currently active nets being routed</span>
            <span class="n">active_nets</span> <span class="o">=</span> <span class="n">nets_in_column</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">][:]</span>

            <span class="k">if</span> <span class="n">col</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">t_net</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">b_net</span><span class="p">:</span>
                <span class="c1"># Nothing happens in the first column if there are no top &amp; bottom nets.</span>
                <span class="c1"># Just continue the active nets from the left-hand face to the next column.</span>
                <span class="n">column_intvls</span> <span class="o">=</span> <span class="p">[]</span>
                <span class="n">next_active_nets</span> <span class="o">=</span> <span class="n">active_nets</span><span class="p">[:]</span>

            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># Bring any nets on the top &amp; bottom of this column into the list of active nets.</span>
                <span class="n">active_nets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">b_net</span>
                <span class="n">active_nets</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">t_net</span>

                <span class="c1"># Generate the intervals that will vertically connect the top &amp; bottom nets to</span>
                <span class="c1"># horizontal tracks in the switchbox.</span>
                <span class="n">column_intvls</span> <span class="o">=</span> <span class="n">connect_top_btm</span><span class="p">(</span><span class="n">active_nets</span><span class="p">)</span>

                <span class="c1"># Add the nets from the new vertical connections to the active nets.</span>
                <span class="n">augmented_active_nets</span> <span class="o">=</span> <span class="n">insert_column_nets</span><span class="p">(</span><span class="n">active_nets</span><span class="p">,</span> <span class="n">column_intvls</span><span class="p">)</span>

                <span class="c1"># Remove the nets processed in this column from the list of target nets.</span>
                <span class="n">targets</span> <span class="o">=</span> <span class="n">prune_targets</span><span class="p">(</span><span class="n">targets</span><span class="p">,</span> <span class="n">col</span><span class="p">)</span>

                <span class="c1"># Insert target nets from rightward columns into this column to direct</span>
                <span class="c1"># the placement of additional vertical intervals towards them.</span>
                <span class="n">augmented_active_nets</span> <span class="o">=</span> <span class="n">insert_target_nets</span><span class="p">(</span>
                    <span class="n">augmented_active_nets</span><span class="p">,</span> <span class="n">targets</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span>
                <span class="p">)</span>

                <span class="c1"># Make vertical connections between tracks in the column having the same net.</span>
                <span class="n">column_intvls</span> <span class="o">=</span> <span class="n">connect_splits</span><span class="p">(</span><span class="n">augmented_active_nets</span><span class="p">,</span> <span class="n">column_intvls</span><span class="p">)</span>

                <span class="c1"># Get the nets that will be active in the next column.</span>
                <span class="n">next_active_nets</span> <span class="o">=</span> <span class="n">extend_tracks</span><span class="p">(</span><span class="n">active_nets</span><span class="p">,</span> <span class="n">column_intvls</span><span class="p">,</span> <span class="n">targets</span><span class="p">)</span>

                <span class="c1"># Trim any hanging stubs from vertical routing intervals in the current column.</span>
                <span class="n">trim_column_intervals</span><span class="p">(</span><span class="n">column_intvls</span><span class="p">,</span> <span class="n">active_nets</span><span class="p">,</span> <span class="n">next_active_nets</span><span class="p">)</span>

            <span class="c1"># Store the active nets for the next column.</span>
            <span class="n">nets_in_column</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">next_active_nets</span><span class="p">)</span>

            <span class="c1"># Store the vertical routing intervals for this column.</span>
            <span class="n">all_column_intvls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">column_intvls</span><span class="p">)</span>

        <span class="c1">########################################</span>
        <span class="c1"># End of switchbox routing loop.</span>
        <span class="c1">########################################</span>

        <span class="c1"># After routing from left-to-right, verify the active track nets coincide</span>
        <span class="c1"># with the positions of the nets on the right-hand face of the switchbox.</span>
        <span class="k">for</span> <span class="n">track_net</span><span class="p">,</span> <span class="n">right_net</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">nets_in_column</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_nets</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">track_net</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">right_net</span><span class="p">:</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;allow_routing_failure&quot;</span><span class="p">):</span>
                    <span class="k">raise</span> <span class="n">SwitchboxRoutingFailure</span>

        <span class="c1"># Create wiring segments along each horizontal track.</span>
        <span class="c1"># Add left and right faces to coordinates of the vertical columns.</span>
        <span class="n">column_coords</span> <span class="o">=</span> <span class="p">(</span>
            <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">]</span>
            <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span>
            <span class="o">+</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">track</span><span class="o">.</span><span class="n">coord</span><span class="p">]</span>
        <span class="p">)</span>
        <span class="c1"># Proceed column-by-column from left-to-right creating horizontal wires.</span>
        <span class="k">for</span> <span class="n">col_idx</span><span class="p">,</span> <span class="n">nets</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">nets_in_column</span><span class="p">):</span>
            <span class="n">beg_col_coord</span> <span class="o">=</span> <span class="n">column_coords</span><span class="p">[</span><span class="n">col_idx</span><span class="p">]</span>
            <span class="n">end_col_coord</span> <span class="o">=</span> <span class="n">column_coords</span><span class="p">[</span><span class="n">col_idx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
            <span class="c1"># Create segments for each track (skipping bottom &amp; top faces).</span>
            <span class="k">for</span> <span class="n">trk_idx</span><span class="p">,</span> <span class="n">net</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">nets</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
                <span class="k">if</span> <span class="n">net</span><span class="p">:</span>
                    <span class="c1"># Create a wire segment for the net in this horizontal track of the column.</span>
                    <span class="n">trk_coord</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">[</span><span class="n">trk_idx</span><span class="p">]</span>
                    <span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">beg_col_coord</span><span class="p">,</span> <span class="n">trk_coord</span><span class="p">)</span>
                    <span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">end_col_coord</span><span class="p">,</span> <span class="n">trk_coord</span><span class="p">)</span>
                    <span class="n">seg</span> <span class="o">=</span> <span class="n">Segment</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">)</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">segments</span><span class="p">[</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

        <span class="c1"># Create vertical wiring segments for each switchbox column.</span>
        <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">column</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">all_column_intvls</span><span class="p">):</span>
            <span class="c1"># Get X coord of this column.</span>
            <span class="n">col_coord</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">column_coords</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
            <span class="c1"># Create vertical wire segments for wire interval in the column.</span>
            <span class="k">for</span> <span class="n">intvl</span> <span class="ow">in</span> <span class="n">column</span><span class="p">:</span>
                <span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">col_coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">beg</span><span class="p">])</span>
                <span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">col_coord</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_coords</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">end</span><span class="p">])</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">segments</span><span class="p">[</span><span class="n">intvl</span><span class="o">.</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Segment</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">))</span>

        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">segments</span>

    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">scr</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">tx</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">font</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">128</span><span class="p">),</span> <span class="n">thickness</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Draw a switchbox and its routing for debugging purposes.</span>

<span class="sd">        Args:</span>
<span class="sd">            scr (PyGame screen): Screen object for PyGame drawing. Initialize PyGame if None.</span>
<span class="sd">            tx (Tx): Transformation matrix from real to screen coords.</span>
<span class="sd">            font (PyGame font): Font for rendering text.</span>
<span class="sd">            color (tuple, optional): Switchbox boundary color. Defaults to (128, 0, 128).</span>
<span class="sd">            thickness (int, optional): Switchbox boundary thickness. Defaults to 2.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># If the screen object is not None, then PyGame drawing is enabled so set flag</span>
        <span class="c1"># to initialize PyGame.</span>
        <span class="n">do_start_end</span> <span class="o">=</span> <span class="ow">not</span> <span class="nb">bool</span><span class="p">(</span><span class="n">scr</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">do_start_end</span><span class="p">:</span>
            <span class="c1"># Initialize PyGame.</span>
            <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span> <span class="o">=</span> <span class="n">draw_start</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">bbox</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="n">DRAWING_BOX_RESIZE</span><span class="p">,</span> <span class="n">DRAWING_BOX_RESIZE</span><span class="p">))</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_switchbox_boundary&quot;</span><span class="p">):</span>
            <span class="c1"># Draw switchbox boundary.</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">thickness</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_switchbox_routing&quot;</span><span class="p">):</span>
            <span class="c1"># Draw routed wire segments.</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">segments</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">segments</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                    <span class="k">for</span> <span class="n">segment</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                        <span class="n">draw_seg</span><span class="p">(</span><span class="n">segment</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
                <span class="k">pass</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_routing_channels&quot;</span><span class="p">):</span>
            <span class="c1"># Draw routing channels from midpoint of one switchbox face to midpoint of another.</span>

            <span class="k">def</span> <span class="nf">draw_channel</span><span class="p">(</span><span class="n">face1</span><span class="p">,</span> <span class="n">face2</span><span class="p">):</span>
                <span class="n">seg1</span> <span class="o">=</span> <span class="n">face1</span><span class="o">.</span><span class="n">seg</span>
                <span class="n">seg2</span> <span class="o">=</span> <span class="n">face2</span><span class="o">.</span><span class="n">seg</span>
                <span class="n">p1</span> <span class="o">=</span> <span class="p">(</span><span class="n">seg1</span><span class="o">.</span><span class="n">p1</span> <span class="o">+</span> <span class="n">seg1</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
                <span class="n">p2</span> <span class="o">=</span> <span class="p">(</span><span class="n">seg2</span><span class="o">.</span><span class="n">p1</span> <span class="o">+</span> <span class="n">seg2</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
                <span class="n">draw_seg</span><span class="p">(</span><span class="n">Segment</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">),</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">128</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="n">dot_radius</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">)</span>
            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="p">)</span>
            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">top_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="p">)</span>
            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="p">)</span>
            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bottom_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="p">)</span>
            <span class="n">draw_channel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">left_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">right_face</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">do_start_end</span><span class="p">:</span>
            <span class="c1"># Terminate PyGame.</span>
            <span class="n">draw_end</span><span class="p">()</span>


<div class="viewcode-block" id="Router">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">class</span> <span class="nc">Router</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Mixin to add routing function to Node class.&quot;&quot;&quot;</span>

<div class="viewcode-block" id="Router.add_routing_points">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.add_routing_points">[docs]</a>
    <span class="k">def</span> <span class="nf">add_routing_points</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">nets</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add routing points by extending wires from pins out to the edge of the part bounding box.</span>

<span class="sd">        Args:</span>
<span class="sd">            nets (list): List of nets to be routed.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">def</span> <span class="nf">add_routing_pt</span><span class="p">(</span><span class="n">pin</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Add the point for a pin on the boundary of a part.&quot;&quot;&quot;</span>

            <span class="n">bbox</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">lbl_bbox</span>
            <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;U&quot;</span><span class="p">:</span>
                <span class="c1"># Pin points up, so extend downward to the bottom of the bounding box.</span>
                <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">y</span>
            <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;D&quot;</span><span class="p">:</span>
                <span class="c1"># Pin points down, so extend upward to the top of the bounding box.</span>
                <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">y</span>
            <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span><span class="p">:</span>
                <span class="c1"># Pin points left, so extend rightward to the right-edge of the bounding box.</span>
                <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">x</span>
            <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span><span class="p">:</span>
                <span class="c1"># Pin points right, so extend leftward to the left-edge of the bounding box.</span>
                <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">x</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Unknown pin orientation.&quot;</span><span class="p">)</span>

        <span class="c1"># Global set of part pin (x,y) points may have stuff from processing previous nodes, so clear it.</span>
        <span class="k">del</span> <span class="n">pin_pts</span><span class="p">[:]</span>  <span class="c1"># Clear the list. Works for Python 2 and 3.</span>

        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">nets</span><span class="p">:</span>
            <span class="c1"># Add routing points for all pins on the net that are inside this node.</span>
            <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_pins</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
                <span class="c1"># Store the point where the pin is. (This is used after routing to trim wire stubs.)</span>
                <span class="n">pin_pts</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pin</span><span class="o">.</span><span class="n">pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">())</span>

                <span class="c1"># Add the point to which the wiring should be extended.</span>
                <span class="n">add_routing_pt</span><span class="p">(</span><span class="n">pin</span><span class="p">)</span>

                <span class="c1"># Add a wire to connect the part pin to the routing point on the bounding box periphery.</span>
                <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span> <span class="o">!=</span> <span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="p">:</span>
                    <span class="n">seg</span> <span class="o">=</span> <span class="n">Segment</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="p">,</span> <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="p">)</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>
                    <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span></div>


<div class="viewcode-block" id="Router.create_routing_tracks">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.create_routing_tracks">[docs]</a>
    <span class="k">def</span> <span class="nf">create_routing_tracks</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">routing_bbox</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create horizontal &amp; vertical global routing tracks.&quot;&quot;&quot;</span>

        <span class="c1"># Find the coords of the horiz/vert tracks that will hold the H/V faces of the routing switchboxes.</span>
        <span class="n">v_track_coord</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">h_track_coord</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># The top/bottom/left/right of each part&#39;s labeled bounding box define the H/V tracks.</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">lbl_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">()</span>
            <span class="n">v_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
            <span class="n">v_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
            <span class="n">h_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
            <span class="n">h_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

        <span class="c1"># Create delimiting tracks around the routing area. Just take the number of nets to be routed</span>
        <span class="c1"># and create a channel that size around the periphery. That&#39;s guaranteed to be big enough.</span>
        <span class="c1"># This is overkill but probably not worth optimizing since any excess boundary area is ignored.</span>
        <span class="n">v_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">routing_bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
        <span class="n">v_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">routing_bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
        <span class="n">h_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">routing_bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
        <span class="n">h_track_coord</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">routing_bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

        <span class="c1"># Remove any duplicate track coords and then sort them.</span>
        <span class="n">v_track_coord</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">v_track_coord</span><span class="p">))</span>
        <span class="n">h_track_coord</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">h_track_coord</span><span class="p">))</span>
        <span class="n">v_track_coord</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
        <span class="n">h_track_coord</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>

        <span class="c1"># Create an H/V track for each H/V coord containing a list for holding the faces in that track.</span>
        <span class="n">v_tracks</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">GlobalTrack</span><span class="p">(</span><span class="n">orientation</span><span class="o">=</span><span class="n">VERT</span><span class="p">,</span> <span class="n">idx</span><span class="o">=</span><span class="n">idx</span><span class="p">,</span> <span class="n">coord</span><span class="o">=</span><span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">coord</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">v_track_coord</span><span class="p">)</span>
        <span class="p">]</span>
        <span class="n">h_tracks</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">GlobalTrack</span><span class="p">(</span><span class="n">orientation</span><span class="o">=</span><span class="n">HORZ</span><span class="p">,</span> <span class="n">idx</span><span class="o">=</span><span class="n">idx</span><span class="p">,</span> <span class="n">coord</span><span class="o">=</span><span class="n">coord</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">coord</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">h_track_coord</span><span class="p">)</span>
        <span class="p">]</span>

        <span class="k">def</span> <span class="nf">bbox_to_faces</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">bbox</span><span class="p">):</span>
            <span class="n">left_track</span> <span class="o">=</span> <span class="n">v_tracks</span><span class="p">[</span><span class="n">v_track_coord</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">x</span><span class="p">)]</span>
            <span class="n">right_track</span> <span class="o">=</span> <span class="n">v_tracks</span><span class="p">[</span><span class="n">v_track_coord</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">x</span><span class="p">)]</span>
            <span class="n">bottom_track</span> <span class="o">=</span> <span class="n">h_tracks</span><span class="p">[</span><span class="n">h_track_coord</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">y</span><span class="p">)]</span>
            <span class="n">top_track</span> <span class="o">=</span> <span class="n">h_tracks</span><span class="p">[</span><span class="n">h_track_coord</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">y</span><span class="p">)]</span>
            <span class="n">Face</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">left_track</span><span class="p">,</span> <span class="n">bottom_track</span><span class="p">,</span> <span class="n">top_track</span><span class="p">)</span>
            <span class="n">Face</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">right_track</span><span class="p">,</span> <span class="n">bottom_track</span><span class="p">,</span> <span class="n">top_track</span><span class="p">)</span>
            <span class="n">Face</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">bottom_track</span><span class="p">,</span> <span class="n">left_track</span><span class="p">,</span> <span class="n">right_track</span><span class="p">)</span>
            <span class="n">Face</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">top_track</span><span class="p">,</span> <span class="n">left_track</span><span class="p">,</span> <span class="n">right_track</span><span class="p">)</span>
            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">Part</span><span class="p">):</span>
                <span class="n">part</span><span class="o">.</span><span class="n">left_track</span> <span class="o">=</span> <span class="n">left_track</span>
                <span class="n">part</span><span class="o">.</span><span class="n">right_track</span> <span class="o">=</span> <span class="n">right_track</span>
                <span class="n">part</span><span class="o">.</span><span class="n">top_track</span> <span class="o">=</span> <span class="n">top_track</span>
                <span class="n">part</span><span class="o">.</span><span class="n">bottom_track</span> <span class="o">=</span> <span class="n">bottom_track</span>

        <span class="c1"># Add routing box faces for each side of a part&#39;s labeled bounding box.</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="n">part_bbox</span> <span class="o">=</span> <span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">lbl_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">()</span>
            <span class="n">bbox_to_faces</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">part_bbox</span><span class="p">)</span>

        <span class="c1"># Add routing box faces for each side of the expanded bounding box surrounding all parts.</span>
        <span class="n">bbox_to_faces</span><span class="p">(</span><span class="n">boundary</span><span class="p">,</span> <span class="n">routing_bbox</span><span class="p">)</span>

        <span class="c1"># Extend the part faces in each horizontal track and then each vertical track.</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">h_tracks</span><span class="p">:</span>
            <span class="n">track</span><span class="o">.</span><span class="n">extend_faces</span><span class="p">(</span><span class="n">v_tracks</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">v_tracks</span><span class="p">:</span>
            <span class="n">track</span><span class="o">.</span><span class="n">extend_faces</span><span class="p">(</span><span class="n">h_tracks</span><span class="p">)</span>

        <span class="c1"># Apply splits to all faces and combine coincident faces.</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">h_tracks</span> <span class="o">+</span> <span class="n">v_tracks</span><span class="p">:</span>
            <span class="n">track</span><span class="o">.</span><span class="n">split_faces</span><span class="p">()</span>
            <span class="n">track</span><span class="o">.</span><span class="n">remove_duplicate_faces</span><span class="p">()</span>

        <span class="c1"># Add adjacencies between faces that define global routing paths within switchboxes.</span>
        <span class="k">for</span> <span class="n">h_track</span> <span class="ow">in</span> <span class="n">h_tracks</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
            <span class="n">h_track</span><span class="o">.</span><span class="n">add_adjacencies</span><span class="p">()</span>

        <span class="k">return</span> <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span></div>


<div class="viewcode-block" id="Router.create_terminals">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.create_terminals">[docs]</a>
    <span class="k">def</span> <span class="nf">create_terminals</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">internal_nets</span><span class="p">,</span> <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create terminals on the faces in the routing tracks.&quot;&quot;&quot;</span>

        <span class="c1"># Add terminals to all non-part/non-boundary faces.</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">h_tracks</span> <span class="o">+</span> <span class="n">v_tracks</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">track</span><span class="p">:</span>
                <span class="n">face</span><span class="o">.</span><span class="n">create_nonpin_terminals</span><span class="p">()</span>

        <span class="c1"># Add terminals to switchbox faces for all part pins on internal nets.</span>
        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">internal_nets</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_pins</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
                <span class="c1"># Find the track (top/bottom/left/right) that the pin is on.</span>
                <span class="n">part</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span>
                <span class="n">pt</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>
                <span class="n">closest_dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">part</span><span class="o">.</span><span class="n">top_track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
                <span class="n">pin_track</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">top_track</span>
                <span class="n">coord</span> <span class="o">=</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span>  <span class="c1"># Pin coord within top track.</span>
                <span class="n">dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">part</span><span class="o">.</span><span class="n">bottom_track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">dist</span> <span class="o">&lt;</span> <span class="n">closest_dist</span><span class="p">:</span>
                    <span class="n">closest_dist</span> <span class="o">=</span> <span class="n">dist</span>
                    <span class="n">pin_track</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">bottom_track</span>
                    <span class="n">coord</span> <span class="o">=</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span>  <span class="c1"># Pin coord within bottom track.</span>
                <span class="n">dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">part</span><span class="o">.</span><span class="n">left_track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">dist</span> <span class="o">&lt;</span> <span class="n">closest_dist</span><span class="p">:</span>
                    <span class="n">closest_dist</span> <span class="o">=</span> <span class="n">dist</span>
                    <span class="n">pin_track</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">left_track</span>
                    <span class="n">coord</span> <span class="o">=</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span>  <span class="c1"># Pin coord within left track.</span>
                <span class="n">dist</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">part</span><span class="o">.</span><span class="n">right_track</span><span class="o">.</span><span class="n">coord</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">dist</span> <span class="o">&lt;</span> <span class="n">closest_dist</span><span class="p">:</span>
                    <span class="n">closest_dist</span> <span class="o">=</span> <span class="n">dist</span>
                    <span class="n">pin_track</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">right_track</span>
                    <span class="n">coord</span> <span class="o">=</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span>  <span class="c1"># Pin coord within right track.</span>

                <span class="c1"># Now search for the face in the track that the pin is on.</span>
                <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">pin_track</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">face</span><span class="o">.</span><span class="n">part</span> <span class="ow">and</span> <span class="n">face</span><span class="o">.</span><span class="n">beg</span><span class="o">.</span><span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">coord</span> <span class="o">&lt;=</span> <span class="n">face</span><span class="o">.</span><span class="n">end</span><span class="o">.</span><span class="n">coord</span><span class="p">:</span>
                        <span class="k">if</span> <span class="ow">not</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="s2">&quot;face&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
                            <span class="c1"># Only assign pin to face if it hasn&#39;t already been assigned to</span>
                            <span class="c1"># another face. This handles the case where a pin is exactly</span>
                            <span class="c1"># at the end coordinate and beginning coordinate of two</span>
                            <span class="c1"># successive faces in the same track.</span>
                            <span class="n">pin</span><span class="o">.</span><span class="n">face</span> <span class="o">=</span> <span class="n">face</span>
                            <span class="n">face</span><span class="o">.</span><span class="n">pins</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pin</span><span class="p">)</span>
                            <span class="n">terminal</span> <span class="o">=</span> <span class="n">Terminal</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">net</span><span class="p">,</span> <span class="n">face</span><span class="p">,</span> <span class="n">coord</span><span class="p">)</span>
                            <span class="n">face</span><span class="o">.</span><span class="n">terminals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">terminal</span><span class="p">)</span>
                        <span class="k">break</span>

        <span class="c1"># Set routing capacity of faces based on # of terminals on each face.</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">h_tracks</span> <span class="o">+</span> <span class="n">v_tracks</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">track</span><span class="p">:</span>
                <span class="n">face</span><span class="o">.</span><span class="n">set_capacity</span><span class="p">()</span></div>


<div class="viewcode-block" id="Router.global_router">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.global_router">[docs]</a>
    <span class="k">def</span> <span class="nf">global_router</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">nets</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Globally route a list of nets from face to face.</span>

<span class="sd">        Args:</span>
<span class="sd">            nets (list): List of Nets to be routed.</span>

<span class="sd">        Returns:</span>
<span class="sd">            List: List of GlobalRoutes.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># This maze router assembles routes from each pin sequentially.</span>
        <span class="c1">#</span>
        <span class="c1"># 1. Find faces with net pins on them and place them on the</span>
        <span class="c1">#    start_faces list.</span>
        <span class="c1"># 2. Randomly select one of the start faces. Add all the other</span>
        <span class="c1">#    faces to the stop_faces list.</span>
        <span class="c1"># 3. Find a route from the start face to closest stop face.</span>
        <span class="c1">#    This concludes the initial phase of the routing.</span>
        <span class="c1"># 4. Iterate through the remaining faces on the start_faces list.</span>
        <span class="c1">#        a. Randomly select a start face.</span>
        <span class="c1">#        b. Set stop faces to be all the faces currently on</span>
        <span class="c1">#           global routes.</span>
        <span class="c1">#        c. Find a route from the start face to any face on</span>
        <span class="c1">#           the global routes, thus enlarging the set of</span>
        <span class="c1">#           contiguous routes while reducing the number of</span>
        <span class="c1">#           unrouted start faces.</span>
        <span class="c1">#        d. Add the faces on the new route to the stop_faces list.</span>

        <span class="c1"># Core routing function.</span>
        <span class="k">def</span> <span class="nf">rt_srch</span><span class="p">(</span><span class="n">start_face</span><span class="p">,</span> <span class="n">stop_faces</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return a minimal-distance path from the start face to one of the stop faces.</span>

<span class="sd">            Args:</span>
<span class="sd">                start_face (Face): Face from which path search begins</span>
<span class="sd">                stop_faces (List): List of Faces at which search will end.</span>

<span class="sd">            Raises:</span>
<span class="sd">                RoutingFailure: No path was found.</span>

<span class="sd">            Returns:</span>
<span class="sd">                GlobalWire: List of Faces from start face to one of the stop faces.</span>
<span class="sd">            &quot;&quot;&quot;</span>

            <span class="c1"># Return empty path if no stop faces or already starting from a stop face.</span>
            <span class="k">if</span> <span class="n">start_face</span> <span class="ow">in</span> <span class="n">stop_faces</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">stop_faces</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">GlobalWire</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>

            <span class="c1"># Record faces that have been visited and their distance from the start face.</span>
            <span class="n">visited_faces</span> <span class="o">=</span> <span class="p">[</span><span class="n">start_face</span><span class="p">]</span>
            <span class="n">start_face</span><span class="o">.</span><span class="n">dist_from_start</span> <span class="o">=</span> <span class="mi">0</span>

            <span class="c1"># Path searches are allowed to touch a Face on a Part if it</span>
            <span class="c1"># has a Pin on the net being routed or if it is one of the stop faces.</span>
            <span class="c1"># This is necessary to allow a search to terminate on a stop face or to</span>
            <span class="c1"># pass through a face with a net pin on the way to finding a connection</span>
            <span class="c1"># to one of the stop faces.</span>
            <span class="n">unconstrained_faces</span> <span class="o">=</span> <span class="n">stop_faces</span> <span class="o">|</span> <span class="n">net_pin_faces</span>

            <span class="c1"># Search through faces until a path is found &amp; returned or a routing exception occurs.</span>
            <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
                <span class="c1"># Set up for finding the closest unvisited face.</span>
                <span class="n">closest_dist</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;inf&quot;</span><span class="p">)</span>
                <span class="n">closest_face</span> <span class="o">=</span> <span class="kc">None</span>

                <span class="c1"># Search for the closest face adjacent to the visited faces.</span>
                <span class="n">visited_faces</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">dist_from_start</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">visited_face</span> <span class="ow">in</span> <span class="n">visited_faces</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">visited_face</span><span class="o">.</span><span class="n">dist_from_start</span> <span class="o">&gt;</span> <span class="n">closest_dist</span><span class="p">:</span>
                        <span class="c1"># Visited face is already further than the current</span>
                        <span class="c1"># closest face, so no use continuing search since</span>
                        <span class="c1"># any remaining visited faces are even more distant.</span>
                        <span class="k">break</span>

                    <span class="c1"># Get the distances to the faces adjacent to this previously-visited face</span>
                    <span class="c1"># and update the closest face if appropriate.</span>
                    <span class="k">for</span> <span class="n">adj</span> <span class="ow">in</span> <span class="n">visited_face</span><span class="o">.</span><span class="n">adjacent</span><span class="p">:</span>
                        <span class="k">if</span> <span class="n">adj</span><span class="o">.</span><span class="n">face</span> <span class="ow">in</span> <span class="n">visited_faces</span><span class="p">:</span>
                            <span class="c1"># Don&#39;t re-visit faces that have already been visited.</span>
                            <span class="k">continue</span>

                        <span class="k">if</span> <span class="p">(</span>
                            <span class="n">adj</span><span class="o">.</span><span class="n">face</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">unconstrained_faces</span>
                            <span class="ow">and</span> <span class="n">adj</span><span class="o">.</span><span class="n">face</span><span class="o">.</span><span class="n">capacity</span> <span class="o">&lt;=</span> <span class="mi">0</span>
                        <span class="p">):</span>
                            <span class="c1"># Skip faces with insufficient routing capacity.</span>
                            <span class="k">continue</span>

                        <span class="c1"># Compute distance of this adjacent face to the start face.</span>
                        <span class="n">dist</span> <span class="o">=</span> <span class="n">visited_face</span><span class="o">.</span><span class="n">dist_from_start</span> <span class="o">+</span> <span class="n">adj</span><span class="o">.</span><span class="n">dist</span>

                        <span class="k">if</span> <span class="n">dist</span> <span class="o">&lt;</span> <span class="n">closest_dist</span><span class="p">:</span>
                            <span class="c1"># Record the closest face seen so far.</span>
                            <span class="n">closest_dist</span> <span class="o">=</span> <span class="n">dist</span>
                            <span class="n">closest_face</span> <span class="o">=</span> <span class="n">adj</span><span class="o">.</span><span class="n">face</span>
                            <span class="n">closest_face</span><span class="o">.</span><span class="n">prev_face</span> <span class="o">=</span> <span class="n">visited_face</span>

                <span class="k">if</span> <span class="ow">not</span> <span class="n">closest_face</span><span class="p">:</span>
                    <span class="c1"># Exception raised if couldn&#39;t find a path from start to stop faces.</span>
                    <span class="k">raise</span> <span class="n">GlobalRoutingFailure</span><span class="p">(</span>
                        <span class="sa">f</span><span class="s2">&quot;Global routing failure: </span><span class="si">{</span><span class="n">net</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">net</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">start_face</span><span class="o">.</span><span class="n">pins</span><span class="si">}</span><span class="s2">&quot;</span>
                    <span class="p">)</span>

                <span class="c1"># Add the closest adjacent face to the list of visited faces.</span>
                <span class="n">closest_face</span><span class="o">.</span><span class="n">dist_from_start</span> <span class="o">=</span> <span class="n">closest_dist</span>
                <span class="n">visited_faces</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">closest_face</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">closest_face</span> <span class="ow">in</span> <span class="n">stop_faces</span><span class="p">:</span>
                    <span class="c1"># The newest, closest face is actually on the list of stop faces, so the search is done.</span>
                    <span class="c1"># Now search back from this face to find the path back to the start face.</span>
                    <span class="n">face_path</span> <span class="o">=</span> <span class="p">[</span><span class="n">closest_face</span><span class="p">]</span>
                    <span class="k">while</span> <span class="n">face_path</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">start_face</span><span class="p">:</span>
                        <span class="n">face_path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">face_path</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">prev_face</span><span class="p">)</span>

                    <span class="c1"># Decrement the routing capacities of the path faces to account for this new routing.</span>
                    <span class="c1"># Don&#39;t decrement the stop face because any routing through it was accounted for</span>
                    <span class="c1"># during a previous routing.</span>
                    <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">face_path</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
                        <span class="k">if</span> <span class="n">face</span><span class="o">.</span><span class="n">capacity</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                            <span class="n">face</span><span class="o">.</span><span class="n">capacity</span> <span class="o">-=</span> <span class="mi">1</span>

                    <span class="c1"># Reverse face path to go from start-to-stop face and return it.</span>
                    <span class="k">return</span> <span class="n">GlobalWire</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">face_path</span><span class="p">))</span>

        <span class="c1"># Key function for setting the order in which nets will be globally routed.</span>
        <span class="k">def</span> <span class="nf">rank_net</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Rank net based on W/H of bounding box of pins and the # of pins.&quot;&quot;&quot;</span>

            <span class="c1"># Nets with a small bounding box probably have fewer routing resources</span>
            <span class="c1"># so they should be routed first.</span>

            <span class="n">bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_pins</span><span class="p">(</span><span class="n">net</span><span class="p">):</span>
                <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span><span class="p">)</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">bbox</span><span class="o">.</span><span class="n">w</span> <span class="o">+</span> <span class="n">bbox</span><span class="o">.</span><span class="n">h</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">pins</span><span class="p">))</span>

        <span class="c1"># Set order in which nets will be routed.</span>
        <span class="n">nets</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">rank_net</span><span class="p">)</span>

        <span class="c1"># Globally route each net.</span>
        <span class="n">global_routes</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">nets</span><span class="p">:</span>
            <span class="c1"># List for storing GlobalWires connecting pins on net.</span>
            <span class="n">global_route</span> <span class="o">=</span> <span class="n">GlobalRoute</span><span class="p">()</span>

            <span class="c1"># Faces with pins from which paths/routing originate.</span>
            <span class="n">net_pin_faces</span> <span class="o">=</span> <span class="p">{</span><span class="n">pin</span><span class="o">.</span><span class="n">face</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_pins</span><span class="p">(</span><span class="n">net</span><span class="p">)}</span>
            <span class="n">start_faces</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">net_pin_faces</span><span class="p">)</span>

            <span class="c1"># Select a random start face and look for a route to *any* of the other start faces.</span>
            <span class="n">start_face</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">start_faces</span><span class="p">))</span>
            <span class="n">start_faces</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">start_face</span><span class="p">)</span>
            <span class="n">stop_faces</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">start_faces</span><span class="p">)</span>
            <span class="n">initial_route</span> <span class="o">=</span> <span class="n">rt_srch</span><span class="p">(</span><span class="n">start_face</span><span class="p">,</span> <span class="n">stop_faces</span><span class="p">)</span>
            <span class="n">global_route</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">initial_route</span><span class="p">)</span>

            <span class="c1"># The faces on the route that was found now become the stopping faces for any further routing.</span>
            <span class="n">stop_faces</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">initial_route</span><span class="p">)</span>

            <span class="c1"># Go thru the other start faces looking for a connection to any existing route.</span>
            <span class="k">for</span> <span class="n">start_face</span> <span class="ow">in</span> <span class="n">start_faces</span><span class="p">:</span>
                <span class="n">next_route</span> <span class="o">=</span> <span class="n">rt_srch</span><span class="p">(</span><span class="n">start_face</span><span class="p">,</span> <span class="n">stop_faces</span><span class="p">)</span>
                <span class="n">global_route</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">next_route</span><span class="p">)</span>

                <span class="c1"># Update the set of stopping faces with the faces on the newest route.</span>
                <span class="n">stop_faces</span> <span class="o">|=</span> <span class="nb">set</span><span class="p">(</span><span class="n">next_route</span><span class="p">)</span>

            <span class="c1"># Add the complete global route for this net to the list of global routes.</span>
            <span class="n">global_routes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">global_route</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">global_routes</span></div>


<div class="viewcode-block" id="Router.create_switchboxes">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.create_switchboxes">[docs]</a>
    <span class="k">def</span> <span class="nf">create_switchboxes</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create routing switchboxes from the faces in the horz/vert tracks.</span>

<span class="sd">        Args:</span>
<span class="sd">            h_tracks (list): List of horizontal Tracks.</span>
<span class="sd">            v_tracks (list): List of vertical Tracks.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values.</span>

<span class="sd">        Returns:</span>
<span class="sd">            list: List of Switchboxes.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Clear any switchboxes associated with faces because we&#39;ll be making new ones.</span>
        <span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">h_tracks</span> <span class="o">+</span> <span class="n">v_tracks</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">track</span><span class="p">:</span>
                <span class="n">face</span><span class="o">.</span><span class="n">switchboxes</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>

        <span class="c1"># For each horizontal Face, create a switchbox where it is the top face of the box.</span>
        <span class="n">switchboxes</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">h_track</span> <span class="ow">in</span> <span class="n">h_tracks</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">h_track</span><span class="p">:</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="c1"># Create a Switchbox with the given Face on top and add it to the list.</span>
                    <span class="n">switchboxes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">SwitchBox</span><span class="p">(</span><span class="n">face</span><span class="p">))</span>
                <span class="k">except</span> <span class="n">NoSwitchBox</span><span class="p">:</span>
                    <span class="k">continue</span>

        <span class="c1"># Check the switchboxes for problems.</span>
        <span class="k">for</span> <span class="n">swbx</span> <span class="ow">in</span> <span class="n">switchboxes</span><span class="p">:</span>
            <span class="n">swbx</span><span class="o">.</span><span class="n">audit</span><span class="p">()</span>

        <span class="c1"># Small switchboxes are more likely to fail routing so try to combine them into larger switchboxes.</span>
        <span class="c1"># Use switchboxes containing nets for routing as seeds for coalescing into larger switchboxes.</span>
        <span class="n">seeds</span> <span class="o">=</span> <span class="p">[</span><span class="n">swbx</span> <span class="k">for</span> <span class="n">swbx</span> <span class="ow">in</span> <span class="n">switchboxes</span> <span class="k">if</span> <span class="n">swbx</span><span class="o">.</span><span class="n">has_nets</span><span class="p">()]</span>

        <span class="c1"># Sort seeds by perimeter so smaller ones are coalesced before larger ones.</span>
        <span class="n">seeds</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">swbx</span><span class="p">:</span> <span class="n">swbx</span><span class="o">.</span><span class="n">bbox</span><span class="o">.</span><span class="n">w</span> <span class="o">+</span> <span class="n">swbx</span><span class="o">.</span><span class="n">bbox</span><span class="o">.</span><span class="n">h</span><span class="p">)</span>

        <span class="c1"># Coalesce smaller switchboxes into larger ones having more routing area.</span>
        <span class="c1"># The smaller switchboxes are removed from the list of switchboxes.</span>
        <span class="n">switchboxes</span> <span class="o">=</span> <span class="p">[</span><span class="n">seed</span><span class="o">.</span><span class="n">coalesce</span><span class="p">(</span><span class="n">switchboxes</span><span class="p">)</span> <span class="k">for</span> <span class="n">seed</span> <span class="ow">in</span> <span class="n">seeds</span><span class="p">]</span>
        <span class="n">switchboxes</span> <span class="o">=</span> <span class="p">[</span><span class="n">swbx</span> <span class="k">for</span> <span class="n">swbx</span> <span class="ow">in</span> <span class="n">switchboxes</span> <span class="k">if</span> <span class="n">swbx</span><span class="p">]</span>  <span class="c1"># Remove None boxes.</span>

        <span class="c1"># A coalesced switchbox may have non-part faces containing multiple terminals</span>
        <span class="c1"># on the same net. Remove all but one to prevent multi-path routes.</span>
        <span class="k">for</span> <span class="n">switchbox</span> <span class="ow">in</span> <span class="n">switchboxes</span><span class="p">:</span>
            <span class="n">switchbox</span><span class="o">.</span><span class="n">trim_repeated_terminals</span><span class="p">()</span>

        <span class="k">return</span> <span class="n">switchboxes</span></div>


<div class="viewcode-block" id="Router.switchbox_router">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.switchbox_router">[docs]</a>
    <span class="k">def</span> <span class="nf">switchbox_router</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">switchboxes</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create detailed wiring between the terminals along the sides of each switchbox.</span>

<span class="sd">        Args:</span>
<span class="sd">            switchboxes (list): List of SwitchBox objects to be individually routed.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values.</span>

<span class="sd">        Returns:</span>
<span class="sd">            None</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Do detailed routing inside each switchbox.</span>
        <span class="c1"># TODO: Switchboxes are independent so could they be routed in parallel?</span>
        <span class="k">for</span> <span class="n">swbx</span> <span class="ow">in</span> <span class="n">switchboxes</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Try routing switchbox from left-to-right.</span>
                <span class="n">swbx</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="k">except</span> <span class="n">RoutingFailure</span><span class="p">:</span>
                <span class="c1"># Routing failed, so try routing top-to-bottom instead.</span>
                <span class="n">swbx</span><span class="o">.</span><span class="n">flip_xy</span><span class="p">()</span>
                <span class="c1"># If this fails, then a routing exception will terminate the whole routing process.</span>
                <span class="n">swbx</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
                <span class="n">swbx</span><span class="o">.</span><span class="n">flip_xy</span><span class="p">()</span>

            <span class="c1"># Add switchbox routes to existing node wiring.</span>
            <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">segments</span> <span class="ow">in</span> <span class="n">swbx</span><span class="o">.</span><span class="n">segments</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="p">[</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span></div>


<div class="viewcode-block" id="Router.cleanup_wires">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.cleanup_wires">[docs]</a>
    <span class="k">def</span> <span class="nf">cleanup_wires</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Try to make wire segments look prettier.&quot;&quot;&quot;</span>

        <span class="k">def</span> <span class="nf">order_seg_points</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Order endpoints in a horizontal or vertical segment.&quot;&quot;&quot;</span>
            <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">&lt;</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">:</span>
                    <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span>

        <span class="k">def</span> <span class="nf">segments_bbox</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return bounding box containing the given list of segments.&quot;&quot;&quot;</span>
            <span class="n">seg_pts</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">chain</span><span class="p">(</span><span class="o">*</span><span class="p">((</span><span class="n">s</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">s</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">)))</span>
            <span class="k">return</span> <span class="n">BBox</span><span class="p">(</span><span class="o">*</span><span class="n">seg_pts</span><span class="p">)</span>

        <span class="k">def</span> <span class="nf">extract_horz_vert_segs</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Separate segments and return lists of horizontal &amp; vertical segments.&quot;&quot;&quot;</span>
            <span class="n">horz_segs</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">]</span>
            <span class="n">vert_segs</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">]</span>
            <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">horz_segs</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">vert_segs</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span>

        <span class="k">def</span> <span class="nf">split_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">,</span> <span class="n">net_pin_pts</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return list of net segments split into the smallest intervals without intersections with other segments.&quot;&quot;&quot;</span>

            <span class="c1"># Check each horizontal segment against each vertical segment and split each one if they intersect.</span>
            <span class="c1"># (This clunky iteration is used so the horz/vert lists can be updated within the loop.)</span>
            <span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span> <span class="o">=</span> <span class="n">extract_horz_vert_segs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>
            <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">horz_segs</span><span class="p">):</span>
                <span class="n">hseg</span> <span class="o">=</span> <span class="n">horz_segs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
                <span class="n">hseg_y</span> <span class="o">=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span>
                <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">while</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">vert_segs</span><span class="p">):</span>
                    <span class="n">vseg</span> <span class="o">=</span> <span class="n">vert_segs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
                    <span class="n">vseg_x</span> <span class="o">=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span>
                    <span class="k">if</span> <span class="p">(</span>
                        <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">vseg_x</span> <span class="o">&lt;=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span>
                        <span class="ow">and</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">hseg_y</span> <span class="o">&lt;=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span>
                    <span class="p">):</span>
                        <span class="n">int_pt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">vseg_x</span><span class="p">,</span> <span class="n">hseg_y</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">int_pt</span> <span class="o">!=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span> <span class="ow">and</span> <span class="n">int_pt</span> <span class="o">!=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="p">:</span>
                            <span class="n">horz_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
                                <span class="n">Segment</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">int_pt</span><span class="p">),</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="p">))</span>
                            <span class="p">)</span>
                            <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">int_pt</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">int_pt</span> <span class="o">!=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span> <span class="ow">and</span> <span class="n">int_pt</span> <span class="o">!=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="p">:</span>
                            <span class="n">vert_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
                                <span class="n">Segment</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">int_pt</span><span class="p">),</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="p">))</span>
                            <span class="p">)</span>
                            <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">int_pt</span><span class="p">)</span>
                    <span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>
                <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>

            <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">horz_segs</span><span class="p">):</span>
                <span class="n">hseg</span> <span class="o">=</span> <span class="n">horz_segs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
                <span class="n">hseg_y</span> <span class="o">=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span>
                <span class="k">for</span> <span class="n">pt</span> <span class="ow">in</span> <span class="n">net_pin_pts</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">hseg_y</span> <span class="ow">and</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                        <span class="n">horz_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Segment</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pt</span><span class="p">),</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="p">)))</span>
                        <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pt</span><span class="p">)</span>
                <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>

            <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">while</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">vert_segs</span><span class="p">):</span>
                <span class="n">vseg</span> <span class="o">=</span> <span class="n">vert_segs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
                <span class="n">vseg_x</span> <span class="o">=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span>
                <span class="k">for</span> <span class="n">pt</span> <span class="ow">in</span> <span class="n">net_pin_pts</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">vseg_x</span> <span class="ow">and</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                        <span class="n">vert_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Segment</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pt</span><span class="p">),</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="p">)))</span>
                        <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pt</span><span class="p">)</span>
                <span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>

            <span class="k">return</span> <span class="n">horz_segs</span> <span class="o">+</span> <span class="n">vert_segs</span>

        <span class="k">def</span> <span class="nf">merge_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return segments after merging those that run the same direction and overlap.&quot;&quot;&quot;</span>

            <span class="c1"># Preprocess the segments.</span>
            <span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span> <span class="o">=</span> <span class="n">extract_horz_vert_segs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="n">merged_segs</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># Separate horizontal segments having the same Y coord.</span>
            <span class="n">horz_segs_v</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">horz_segs</span><span class="p">:</span>
                <span class="n">horz_segs_v</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

            <span class="c1"># Merge overlapping segments having the same Y coord.</span>
            <span class="k">for</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">horz_segs_v</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                <span class="c1"># Order segments by their starting X coord.</span>
                <span class="n">segs</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">s</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
                <span class="c1"># Append first segment to list of merged segments.</span>
                <span class="n">merged_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">segs</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
                <span class="c1"># Go thru the remaining segments looking for overlaps with the last entry on the merge list.</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segs</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
                    <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                        <span class="c1"># Segments overlap, so update the extent of the last entry.</span>
                        <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># No overlap, so append the current segment to the merge list and use it for</span>
                        <span class="c1"># further checks of intersection with remaining segments.</span>
                        <span class="n">merged_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

            <span class="c1"># Separate vertical segments having the same X coord.</span>
            <span class="n">vert_segs_h</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">vert_segs</span><span class="p">:</span>
                <span class="n">vert_segs_h</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

            <span class="c1"># Merge overlapping segments having the same X coord.</span>
            <span class="k">for</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">vert_segs_h</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                <span class="c1"># Order segments by their starting Y coord.</span>
                <span class="n">segs</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">s</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
                <span class="c1"># Append first segment to list of merged segments.</span>
                <span class="n">merged_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">segs</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
                <span class="c1"># Go thru the remaining segments looking for overlaps with the last entry on the merge list.</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segs</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
                    <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                        <span class="c1"># Segments overlap, so update the extent of the last entry.</span>
                        <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">merged_segs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># No overlap, so append the current segment to the merge list and use it for</span>
                        <span class="c1"># further checks of intersection with remaining segments.</span>
                        <span class="n">merged_segs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

            <span class="k">return</span> <span class="n">merged_segs</span>

        <span class="k">def</span> <span class="nf">break_cycles</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Remove segments to break any cycles of a net&#39;s segments.&quot;&quot;&quot;</span>

            <span class="c1"># Create a dict storing set of segments adjacent to each endpoint.</span>
            <span class="n">adj_segs</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">set</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                <span class="c1"># Add segment to set for each endpoint.</span>
                <span class="n">adj_segs</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>
                <span class="n">adj_segs</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

            <span class="c1"># Create a dict storing the list of endpoints adjacent to each endpoint.</span>
            <span class="n">adj_pts</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">pt</span><span class="p">,</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">adj_segs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="c1"># Store endpoints of all segments adjacent to endpoint, then remove the endpoint.</span>
                <span class="n">adj_pts</span><span class="p">[</span><span class="n">pt</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">({</span><span class="n">p</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segs</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">)})</span>
                <span class="n">adj_pts</span><span class="p">[</span><span class="n">pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">pt</span><span class="p">)</span>

            <span class="c1"># Start at any endpoint and visit adjacent endpoints until all have been visited.</span>
            <span class="c1"># If an endpoint is seen more than once, then a cycle exists. Remove the segment forming the cycle.</span>
            <span class="n">visited_pts</span> <span class="o">=</span> <span class="p">[]</span>  <span class="c1"># List of visited endpoints.</span>
            <span class="n">frontier_pts</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">adj_pts</span><span class="o">.</span><span class="n">keys</span><span class="p">())[:</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># Arbitrary starting point.</span>
            <span class="k">while</span> <span class="n">frontier_pts</span><span class="p">:</span>
                <span class="c1"># Visit a point on the frontier.</span>
                <span class="n">frontier_pt</span> <span class="o">=</span> <span class="n">frontier_pts</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
                <span class="n">visited_pts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">frontier_pt</span><span class="p">)</span>

                <span class="c1"># Check each adjacent endpoint for cycles.</span>
                <span class="k">for</span> <span class="n">adj_pt</span> <span class="ow">in</span> <span class="n">adj_pts</span><span class="p">[</span><span class="n">frontier_pt</span><span class="p">][:]:</span>
                    <span class="k">if</span> <span class="n">adj_pt</span> <span class="ow">in</span> <span class="n">visited_pts</span> <span class="o">+</span> <span class="n">frontier_pts</span><span class="p">:</span>
                        <span class="c1"># This point was already reached by another path so there is a cycle.</span>
                        <span class="c1"># Break it by removing segment between frontier_pt and adj_pt.</span>
                        <span class="n">loop_seg</span> <span class="o">=</span> <span class="p">(</span><span class="n">adj_segs</span><span class="p">[</span><span class="n">frontier_pt</span><span class="p">]</span> <span class="o">&amp;</span> <span class="n">adj_segs</span><span class="p">[</span><span class="n">adj_pt</span><span class="p">])</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
                        <span class="n">segments</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">loop_seg</span><span class="p">)</span>
                        <span class="n">adj_segs</span><span class="p">[</span><span class="n">frontier_pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">loop_seg</span><span class="p">)</span>
                        <span class="n">adj_segs</span><span class="p">[</span><span class="n">adj_pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">loop_seg</span><span class="p">)</span>
                        <span class="n">adj_pts</span><span class="p">[</span><span class="n">frontier_pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">adj_pt</span><span class="p">)</span>
                        <span class="n">adj_pts</span><span class="p">[</span><span class="n">adj_pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">frontier_pt</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># First time adjacent point has been reached, so add it to frontier.</span>
                        <span class="n">frontier_pts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">adj_pt</span><span class="p">)</span>
                        <span class="c1"># Keep this new frontier point from backtracking to the current frontier point later.</span>
                        <span class="n">adj_pts</span><span class="p">[</span><span class="n">adj_pt</span><span class="p">]</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">frontier_pt</span><span class="p">)</span>

            <span class="k">return</span> <span class="n">segments</span>

        <span class="k">def</span> <span class="nf">is_pin_pt</span><span class="p">(</span><span class="n">pt</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return True if the point is on one of the part pins.&quot;&quot;&quot;</span>
            <span class="k">return</span> <span class="n">pt</span> <span class="ow">in</span> <span class="n">pin_pts</span>

        <span class="k">def</span> <span class="nf">contains_pt</span><span class="p">(</span><span class="n">seg</span><span class="p">,</span> <span class="n">pt</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return True if the point is contained within the horz/vert segment.&quot;&quot;&quot;</span>
            <span class="k">return</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="ow">and</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span>

        <span class="k">def</span> <span class="nf">trim_stubs</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Return segments after removing stubs that have an unconnected endpoint.&quot;&quot;&quot;</span>

            <span class="k">def</span> <span class="nf">get_stubs</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Return set of stub segments.&quot;&quot;&quot;</span>

                <span class="c1"># For end point, the dict entry contains a list of the segments that meet there.</span>
                <span class="n">stubs</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>

                <span class="c1"># Process the segments looking for points that are on only a single segment.</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                    <span class="c1"># Add the segment to the segment list of each end point.</span>
                    <span class="n">stubs</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>
                    <span class="n">stubs</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

                <span class="c1"># Keep only the segments with an unconnected endpoint that is not on a part pin.</span>
                <span class="n">stubs</span> <span class="o">=</span> <span class="p">{</span>
                    <span class="n">segs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
                    <span class="k">for</span> <span class="n">endpt</span><span class="p">,</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">stubs</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">segs</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">is_pin_pt</span><span class="p">(</span><span class="n">endpt</span><span class="p">)</span>
                <span class="p">}</span>
                <span class="k">return</span> <span class="n">stubs</span>

            <span class="n">trimmed_segments</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">segments</span><span class="p">[:])</span>
            <span class="n">stubs</span> <span class="o">=</span> <span class="n">get_stubs</span><span class="p">(</span><span class="n">trimmed_segments</span><span class="p">)</span>
            <span class="k">while</span> <span class="n">stubs</span><span class="p">:</span>
                <span class="n">trimmed_segments</span> <span class="o">-=</span> <span class="n">stubs</span>
                <span class="n">stubs</span> <span class="o">=</span> <span class="n">get_stubs</span><span class="p">(</span><span class="n">trimmed_segments</span><span class="p">)</span>
            <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">trimmed_segments</span><span class="p">)</span>

        <span class="k">def</span> <span class="nf">remove_jogs_old</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">segments</span><span class="p">,</span> <span class="n">wires</span><span class="p">,</span> <span class="n">net_bboxes</span><span class="p">,</span> <span class="n">part_bboxes</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Remove jogs in wiring segments.</span>

<span class="sd">            Args:</span>
<span class="sd">                net (Net): Net whose wire segments will be modified.</span>
<span class="sd">                segments (list): List of wire segments for the given net.</span>
<span class="sd">                wires (dict): Dict of lists of wire segments indexed by nets.</span>
<span class="sd">                net_bboxes (dict): Dict of BBoxes for wire segments indexed by nets.</span>
<span class="sd">                part_bboxes (list): List of BBoxes for the placed parts.</span>
<span class="sd">            &quot;&quot;&quot;</span>

            <span class="k">def</span> <span class="nf">get_touching_segs</span><span class="p">(</span><span class="n">seg</span><span class="p">,</span> <span class="n">ortho_segs</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Return list of orthogonal segments that touch the given segment.&quot;&quot;&quot;</span>
                <span class="n">touch_segs</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">oseg</span> <span class="ow">in</span> <span class="n">ortho_segs</span><span class="p">:</span>
                    <span class="c1"># oseg horz, seg vert. Do they intersect?</span>
                    <span class="k">if</span> <span class="n">contains_pt</span><span class="p">(</span><span class="n">oseg</span><span class="p">,</span> <span class="n">Point</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">oseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">)):</span>
                        <span class="n">touch_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">oseg</span><span class="p">)</span>
                    <span class="c1"># oseg vert, seg horz. Do they intersect?</span>
                    <span class="k">elif</span> <span class="n">contains_pt</span><span class="p">(</span><span class="n">oseg</span><span class="p">,</span> <span class="n">Point</span><span class="p">(</span><span class="n">oseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">)):</span>
                        <span class="n">touch_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">oseg</span><span class="p">)</span>
                <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">touch_segs</span><span class="p">)</span>  <span class="c1"># Convert to list with no dups.</span>

            <span class="k">def</span> <span class="nf">get_overlap</span><span class="p">(</span><span class="o">*</span><span class="n">segs</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Find extent of overlap of parallel horz/vert segments and return as (min, max) tuple.&quot;&quot;&quot;</span>
                <span class="n">ov1</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;-inf&quot;</span><span class="p">)</span>
                <span class="n">ov2</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;inf&quot;</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segs</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                        <span class="c1"># Horizontal segment.</span>
                        <span class="n">p1</span><span class="p">,</span> <span class="n">p2</span> <span class="o">=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># Vertical segment.</span>
                        <span class="n">p1</span><span class="p">,</span> <span class="n">p2</span> <span class="o">=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span>
                    <span class="n">ov1</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">ov1</span><span class="p">,</span> <span class="n">p1</span><span class="p">)</span>  <span class="c1"># Max of extent minimums.</span>
                    <span class="n">ov2</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">ov2</span><span class="p">,</span> <span class="n">p2</span><span class="p">)</span>  <span class="c1"># Min of extent maximums.</span>
                <span class="c1"># assert ov1 &lt;= ov2</span>
                <span class="k">return</span> <span class="n">ov1</span><span class="p">,</span> <span class="n">ov2</span>

            <span class="k">def</span> <span class="nf">obstructed</span><span class="p">(</span><span class="n">segment</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Return true if segment obstructed by parts or segments of other nets.&quot;&quot;&quot;</span>

                <span class="c1"># Obstructed if segment bbox intersects one of the part bboxes.</span>
                <span class="n">segment_bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">(</span><span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">part_bbox</span> <span class="ow">in</span> <span class="n">part_bboxes</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">part_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">segment_bbox</span><span class="p">):</span>
                        <span class="k">return</span> <span class="kc">True</span>

                <span class="c1"># BBoxes don&#39;t intersect if they line up exactly edge-to-edge.</span>
                <span class="c1"># So expand the segment bbox slightly so intersections with bboxes of</span>
                <span class="c1"># other segments will be detected.</span>
                <span class="n">segment_bbox</span> <span class="o">=</span> <span class="n">segment_bbox</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>

                <span class="c1"># Look for an overlay intersection with a segment of another net.</span>
                <span class="k">for</span> <span class="n">nt</span><span class="p">,</span> <span class="n">nt_bbox</span> <span class="ow">in</span> <span class="n">net_bboxes</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                    <span class="k">if</span> <span class="n">nt</span> <span class="ow">is</span> <span class="n">net</span><span class="p">:</span>
                        <span class="c1"># Don&#39;t check this segment with other segments of its own net.</span>
                        <span class="k">continue</span>

                    <span class="k">if</span> <span class="ow">not</span> <span class="n">segment_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">nt_bbox</span><span class="p">):</span>
                        <span class="c1"># Don&#39;t check this segment against segments of another net whose</span>
                        <span class="c1"># bbox doesn&#39;t even intersect this segment.</span>
                        <span class="k">continue</span>

                    <span class="c1"># Check for overlay intersectionss between this segment and the</span>
                    <span class="c1"># parallel segments of the other net.</span>
                    <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">wires</span><span class="p">[</span><span class="n">nt</span><span class="p">]:</span>
                        <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                            <span class="c1"># Segments are both aligned vertically on the same track X coord.</span>
                            <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="ow">and</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">&gt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                                <span class="c1"># Segments overlap so segment is obstructed.</span>
                                <span class="k">return</span> <span class="kc">True</span>
                        <span class="k">elif</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                            <span class="c1"># Segments are both aligned horizontally on the same track Y coord.</span>
                            <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="ow">and</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">&gt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                                <span class="c1"># Segments overlap so segment is obstructed.</span>
                                <span class="k">return</span> <span class="kc">True</span>

                <span class="c1"># No obstructions found, so return False.</span>
                <span class="k">return</span> <span class="kc">False</span>

            <span class="c1"># Make sure p1 &lt;= p2 for segment endpoints.</span>
            <span class="n">order_seg_points</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Split segments into horizontal/vertical groups.</span>
            <span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span> <span class="o">=</span> <span class="n">extract_horz_vert_segs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Look for a segment touched by ends of orthogonal segments all pointing in the same direction.</span>
            <span class="c1"># Then slide this segment to the other end of the interval by which the touching segments</span>
            <span class="c1"># overlap. This will reduce or eliminate the jog.</span>
            <span class="n">stop</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="k">for</span> <span class="n">segs</span><span class="p">,</span> <span class="n">ortho_segs</span> <span class="ow">in</span> <span class="p">((</span><span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span><span class="p">),</span> <span class="p">(</span><span class="n">vert_segs</span><span class="p">,</span> <span class="n">horz_segs</span><span class="p">)):</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segs</span><span class="p">:</span>
                    <span class="c1"># Don&#39;t move a segment if one of its endpoints connects to a part pin.</span>
                    <span class="k">if</span> <span class="n">is_pin_pt</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">)</span> <span class="ow">or</span> <span class="n">is_pin_pt</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">):</span>
                        <span class="k">continue</span>

                    <span class="c1"># Find all orthogonal segments that touch this one.</span>
                    <span class="n">touching_segs</span> <span class="o">=</span> <span class="n">get_touching_segs</span><span class="p">(</span><span class="n">seg</span><span class="p">,</span> <span class="n">ortho_segs</span><span class="p">)</span>

                    <span class="c1"># Find extent of overlap of all orthogonal segments.</span>
                    <span class="n">ov1</span><span class="p">,</span> <span class="n">ov2</span> <span class="o">=</span> <span class="n">get_overlap</span><span class="p">(</span><span class="o">*</span><span class="n">touching_segs</span><span class="p">)</span>

                    <span class="k">if</span> <span class="n">ov1</span> <span class="o">&gt;=</span> <span class="n">ov2</span><span class="p">:</span>
                        <span class="c1"># No overlap, so this segment can&#39;t be moved one way or the other.</span>
                        <span class="k">continue</span>

                    <span class="k">if</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">horz_segs</span><span class="p">:</span>
                        <span class="c1"># Move horz segment vertically to other end of overlap to remove jog.</span>
                        <span class="n">test_seg</span> <span class="o">=</span> <span class="n">Segment</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>
                        <span class="n">seg_y</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span>
                        <span class="k">if</span> <span class="n">seg_y</span> <span class="o">==</span> <span class="n">ov1</span><span class="p">:</span>
                            <span class="c1"># Segment is at one end of the overlay, so move it to the other end.</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ov2</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ov2</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">obstructed</span><span class="p">(</span><span class="n">test_seg</span><span class="p">):</span>
                                <span class="c1"># Segment move is not obstructed, so accept it.</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span>
                                <span class="c1"># If one segment is moved, maybe more can be moved so don&#39;t stop.</span>
                                <span class="n">stop</span> <span class="o">=</span> <span class="kc">False</span>
                        <span class="k">elif</span> <span class="n">seg_y</span> <span class="o">==</span> <span class="n">ov2</span><span class="p">:</span>
                            <span class="c1"># Segment is at one end of the overlay, so move it to the other end.</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ov1</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ov1</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">obstructed</span><span class="p">(</span><span class="n">test_seg</span><span class="p">):</span>
                                <span class="c1"># Segment move is not obstructed, so accept it.</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span>
                                <span class="c1"># If one segment is moved, maybe more can be moved so don&#39;t stop.</span>
                                <span class="n">stop</span> <span class="o">=</span> <span class="kc">False</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="c1"># Segment in interior of overlay, so it&#39;s not a jog. Don&#39;t move it.</span>
                            <span class="k">pass</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="c1"># Move vert segment horizontally to other end of overlap to remove jog.</span>
                        <span class="n">test_seg</span> <span class="o">=</span> <span class="n">Segment</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>
                        <span class="n">seg_x</span> <span class="o">=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span>
                        <span class="k">if</span> <span class="n">seg_x</span> <span class="o">==</span> <span class="n">ov1</span><span class="p">:</span>
                            <span class="c1"># Segment is at one end of the overlay, so move it to the other end.</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">ov2</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">ov2</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">obstructed</span><span class="p">(</span><span class="n">test_seg</span><span class="p">):</span>
                                <span class="c1"># Segment move is not obstructed, so accept it.</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span>
                                <span class="c1"># If one segment is moved, maybe more can be moved so don&#39;t stop.</span>
                                <span class="n">stop</span> <span class="o">=</span> <span class="kc">False</span>
                        <span class="k">elif</span> <span class="n">seg_x</span> <span class="o">==</span> <span class="n">ov2</span><span class="p">:</span>
                            <span class="c1"># Segment is at one end of the overlay, so move it to the other end.</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">ov1</span>
                            <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">ov1</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">obstructed</span><span class="p">(</span><span class="n">test_seg</span><span class="p">):</span>
                                <span class="c1"># Segment move is not obstructed, so accept it.</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p1</span>
                                <span class="n">seg</span><span class="o">.</span><span class="n">p2</span> <span class="o">=</span> <span class="n">test_seg</span><span class="o">.</span><span class="n">p2</span>
                                <span class="c1"># If one segment is moved, maybe more can be moved so don&#39;t stop.</span>
                                <span class="n">stop</span> <span class="o">=</span> <span class="kc">False</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="c1"># Segment in interior of overlay, so it&#39;s not a jog. Don&#39;t move it.</span>
                            <span class="k">pass</span>

            <span class="c1"># Return updated segments. If no segments for this net were updated, then stop is True.</span>
            <span class="k">return</span> <span class="n">segments</span><span class="p">,</span> <span class="n">stop</span>

        <span class="k">def</span> <span class="nf">remove_jogs</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">segments</span><span class="p">,</span> <span class="n">wires</span><span class="p">,</span> <span class="n">net_bboxes</span><span class="p">,</span> <span class="n">part_bboxes</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Remove jogs and staircases in wiring segments.</span>

<span class="sd">            Args:</span>
<span class="sd">                net (Net): Net whose wire segments will be modified.</span>
<span class="sd">                segments (list): List of wire segments for the given net.</span>
<span class="sd">                wires (dict): Dict of lists of wire segments indexed by nets.</span>
<span class="sd">                net_bboxes (dict): Dict of BBoxes for wire segments indexed by nets.</span>
<span class="sd">                part_bboxes (list): List of BBoxes for the placed parts.</span>
<span class="sd">            &quot;&quot;&quot;</span>

            <span class="k">def</span> <span class="nf">obstructed</span><span class="p">(</span><span class="n">segment</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Return true if segment obstructed by parts or segments of other nets.&quot;&quot;&quot;</span>

                <span class="c1"># Obstructed if segment bbox intersects one of the part bboxes.</span>
                <span class="n">segment_bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">(</span><span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="p">,</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">part_bbox</span> <span class="ow">in</span> <span class="n">part_bboxes</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">part_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">segment_bbox</span><span class="p">):</span>
                        <span class="k">return</span> <span class="kc">True</span>

                <span class="c1"># BBoxes don&#39;t intersect if they line up exactly edge-to-edge.</span>
                <span class="c1"># So expand the segment bbox slightly so intersections with bboxes of</span>
                <span class="c1"># other segments will be detected.</span>
                <span class="n">segment_bbox</span> <span class="o">=</span> <span class="n">segment_bbox</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>

                <span class="c1"># Look for an overlay intersection with a segment of another net.</span>
                <span class="k">for</span> <span class="n">nt</span><span class="p">,</span> <span class="n">nt_bbox</span> <span class="ow">in</span> <span class="n">net_bboxes</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                    <span class="k">if</span> <span class="n">nt</span> <span class="ow">is</span> <span class="n">net</span><span class="p">:</span>
                        <span class="c1"># Don&#39;t check this segment with other segments of its own net.</span>
                        <span class="k">continue</span>

                    <span class="k">if</span> <span class="ow">not</span> <span class="n">segment_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">nt_bbox</span><span class="p">):</span>
                        <span class="c1"># Don&#39;t check this segment against segments of another net whose</span>
                        <span class="c1"># bbox doesn&#39;t even intersect this segment.</span>
                        <span class="k">continue</span>

                    <span class="c1"># Check for overlay intersectionss between this segment and the</span>
                    <span class="c1"># parallel segments of the other net.</span>
                    <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">wires</span><span class="p">[</span><span class="n">nt</span><span class="p">]:</span>
                        <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                            <span class="c1"># Segments are both aligned vertically on the same track X coord.</span>
                            <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="ow">and</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">&gt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                                <span class="c1"># Segments overlap so segment is obstructed.</span>
                                <span class="k">return</span> <span class="kc">True</span>
                        <span class="k">elif</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">:</span>
                            <span class="c1"># Segments are both aligned horizontally on the same track Y coord.</span>
                            <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="ow">and</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span> <span class="o">&gt;=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">:</span>
                                <span class="c1"># Segments overlap so segment is obstructed.</span>
                                <span class="k">return</span> <span class="kc">True</span>

                <span class="c1"># No obstructions found, so return False.</span>
                <span class="k">return</span> <span class="kc">False</span>

            <span class="k">def</span> <span class="nf">get_corners</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Return dictionary of right-angle corner points and lists of associated segments.&quot;&quot;&quot;</span>

                <span class="c1"># For each corner point, the dict entry contains a list of the segments that meet there.</span>
                <span class="n">corners</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>

                <span class="c1"># Process the segments so that any potential right-angle corner has the horizontal</span>
                <span class="c1"># segment followed by the vertical segment.</span>
                <span class="n">horz_segs</span><span class="p">,</span> <span class="n">vert_segs</span> <span class="o">=</span> <span class="n">extract_horz_vert_segs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">horz_segs</span> <span class="o">+</span> <span class="n">vert_segs</span><span class="p">:</span>
                    <span class="c1"># Add the segment to the segment list of each end point.</span>
                    <span class="n">corners</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>
                    <span class="n">corners</span><span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>

                <span class="c1"># Keep only the corner points where two segments meet at right angles at a point not on a part pin.</span>
                <span class="n">corners</span> <span class="o">=</span> <span class="p">{</span>
                    <span class="n">corner</span><span class="p">:</span> <span class="n">segs</span>
                    <span class="k">for</span> <span class="n">corner</span><span class="p">,</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">corners</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">segs</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span>
                    <span class="ow">and</span> <span class="ow">not</span> <span class="n">is_pin_pt</span><span class="p">(</span><span class="n">corner</span><span class="p">)</span>
                    <span class="ow">and</span> <span class="n">segs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="n">horz_segs</span>
                    <span class="ow">and</span> <span class="n">segs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">in</span> <span class="n">vert_segs</span>
                <span class="p">}</span>
                <span class="k">return</span> <span class="n">corners</span>

            <span class="k">def</span> <span class="nf">get_jogs</span><span class="p">(</span><span class="n">segments</span><span class="p">):</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;Yield the three segments and starting and end points of a staircase or tophat jog.&quot;&quot;&quot;</span>

                <span class="c1"># Get dict of right-angle corners formed by segments.</span>
                <span class="n">corners</span> <span class="o">=</span> <span class="n">get_corners</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

                <span class="c1"># Look for segments with both endpoints on right-angle corners, indicating this segment</span>
                <span class="c1"># is in the middle of a three-segment staircase or tophat jog.</span>
                <span class="k">for</span> <span class="n">segment</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">segment</span><span class="o">.</span><span class="n">p1</span> <span class="ow">in</span> <span class="n">corners</span> <span class="ow">and</span> <span class="n">segment</span><span class="o">.</span><span class="n">p2</span> <span class="ow">in</span> <span class="n">corners</span><span class="p">:</span>
                        <span class="c1"># Get the three segments in the jog.</span>
                        <span class="n">jog_segs</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                        <span class="n">jog_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">corners</span><span class="p">[</span><span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
                        <span class="n">jog_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">corners</span><span class="p">[</span><span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>
                        <span class="n">jog_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">corners</span><span class="p">[</span><span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
                        <span class="n">jog_segs</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">corners</span><span class="p">[</span><span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>

                        <span class="c1"># Get the points where the three-segment jog starts and stops.</span>
                        <span class="n">start_stop_pts</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                        <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">jog_segs</span><span class="p">:</span>
                            <span class="n">start_stop_pts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="p">)</span>
                            <span class="n">start_stop_pts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>
                        <span class="n">start_stop_pts</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">segment</span><span class="o">.</span><span class="n">p1</span><span class="p">)</span>
                        <span class="n">start_stop_pts</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">segment</span><span class="o">.</span><span class="n">p2</span><span class="p">)</span>

                        <span class="c1"># Send the jog that was found.</span>
                        <span class="k">yield</span> <span class="nb">list</span><span class="p">(</span><span class="n">jog_segs</span><span class="p">),</span> <span class="nb">list</span><span class="p">(</span><span class="n">start_stop_pts</span><span class="p">)</span>

            <span class="c1"># Shuffle segments to vary the order of detected jogs.</span>
            <span class="n">random</span><span class="o">.</span><span class="n">shuffle</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Get iterator for jogs.</span>
            <span class="n">jogs</span> <span class="o">=</span> <span class="n">get_jogs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Search for jogs and break from the loop if a correctable jog is found or we run out of jogs.</span>
            <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
                <span class="c1"># Get the segments and start-stop points for the next jog.</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="n">jog_segs</span><span class="p">,</span> <span class="n">start_stop_pts</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">jogs</span><span class="p">)</span>
                <span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span>
                    <span class="c1"># No more jogs and no corrections made, so return segments and stop flag is true.</span>
                    <span class="k">return</span> <span class="n">segments</span><span class="p">,</span> <span class="kc">True</span>

                <span class="c1"># Get the start-stop points and order them so p1 &lt; p3.</span>
                <span class="n">p1</span><span class="p">,</span> <span class="n">p3</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">start_stop_pts</span><span class="p">)</span>

                <span class="c1"># These are the potential routing points for correcting the jog.</span>
                <span class="c1"># Either start at p1 and move vertically and then horizontally to p3, or</span>
                <span class="c1"># move horizontally from p1 and then vertically to p3.</span>
                <span class="n">p2s</span> <span class="o">=</span> <span class="p">[</span><span class="n">Point</span><span class="p">(</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p3</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">Point</span><span class="p">(</span><span class="n">p3</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p1</span><span class="o">.</span><span class="n">y</span><span class="p">)]</span>

                <span class="c1"># Shuffle the routing points so the applied correction isn&#39;t always the same orientation.</span>
                <span class="n">random</span><span class="o">.</span><span class="n">shuffle</span><span class="p">(</span><span class="n">p2s</span><span class="p">)</span>

                <span class="c1"># Check each routing point to see if it leads to a valid routing.</span>
                <span class="k">for</span> <span class="n">p2</span> <span class="ow">in</span> <span class="n">p2s</span><span class="p">:</span>
                    <span class="c1"># Replace the three-segment jog with these two right-angle segments.</span>
                    <span class="n">new_segs</span> <span class="o">=</span> <span class="p">[</span>
                        <span class="n">Segment</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pa</span><span class="p">),</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">pb</span><span class="p">))</span>
                        <span class="k">for</span> <span class="n">pa</span><span class="p">,</span> <span class="n">pb</span> <span class="ow">in</span> <span class="p">((</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">),</span> <span class="p">(</span><span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">))</span>
                        <span class="k">if</span> <span class="n">pa</span> <span class="o">!=</span> <span class="n">pb</span>
                    <span class="p">]</span>
                    <span class="n">order_seg_points</span><span class="p">(</span><span class="n">new_segs</span><span class="p">)</span>

                    <span class="c1"># Check the new segments to see if they run into parts or segments of other nets.</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">((</span><span class="n">obstructed</span><span class="p">(</span><span class="n">new_seg</span><span class="p">)</span> <span class="k">for</span> <span class="n">new_seg</span> <span class="ow">in</span> <span class="n">new_segs</span><span class="p">)):</span>
                        <span class="c1"># OK, segments are good so replace the old segments in the jog with them.</span>
                        <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">jog_segs</span><span class="p">:</span>
                            <span class="n">segments</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">seg</span><span class="p">)</span>
                        <span class="n">segments</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">new_segs</span><span class="p">)</span>

                        <span class="c1"># Return updated segments and set stop flag to false because segments were modified.</span>
                        <span class="k">return</span> <span class="n">segments</span><span class="p">,</span> <span class="kc">False</span>

        <span class="c1"># Get part bounding boxes so parts can be avoided when modifying net segments.</span>
        <span class="n">part_bboxes</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">bbox</span> <span class="o">*</span> <span class="n">p</span><span class="o">.</span><span class="n">tx</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">]</span>

        <span class="c1"># Get dict of bounding boxes for the nets in this node.</span>
        <span class="n">net_bboxes</span> <span class="o">=</span> <span class="p">{</span><span class="n">net</span><span class="p">:</span> <span class="n">segments_bbox</span><span class="p">(</span><span class="n">segs</span><span class="p">)</span> <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">segs</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>

        <span class="c1"># Get locations for part pins of each net. (For use when splitting net segments.)</span>
        <span class="n">net_pin_pts</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
            <span class="n">net_pin_pts</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
                <span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">()</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_pins</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>
            <span class="p">]</span>

        <span class="c1"># Do a generalized cleanup of the wire segments of each net.</span>
        <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">segments</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># Round the wire segment endpoints to integers.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span><span class="o">.</span><span class="n">round</span><span class="p">()</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span><span class="p">]</span>

            <span class="c1"># Keep only non zero-length segments.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">!=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span>

            <span class="c1"># Make sure the segment endpoints are in the right order.</span>
            <span class="n">order_seg_points</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Merge colinear, overlapping segments. Also removes any duplicated segments.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="n">merge_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Split intersecting segments.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="n">split_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">,</span> <span class="n">net_pin_pts</span><span class="p">[</span><span class="n">net</span><span class="p">])</span>

            <span class="c1"># Break loops of segments.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="n">break_cycles</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="c1"># Keep only non zero-length segments.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">!=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span>

            <span class="c1"># Trim wire stubs.</span>
            <span class="n">segments</span> <span class="o">=</span> <span class="n">trim_stubs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

            <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="n">segments</span>

        <span class="c1"># Remove jogs in the wire segments of each net.</span>
        <span class="n">keep_cleaning</span> <span class="o">=</span> <span class="kc">True</span>
        <span class="k">while</span> <span class="n">keep_cleaning</span><span class="p">:</span>
            <span class="n">keep_cleaning</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">segments</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
                    <span class="c1"># Split intersecting segments.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="n">split_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">,</span> <span class="n">net_pin_pts</span><span class="p">[</span><span class="n">net</span><span class="p">])</span>

                    <span class="c1"># Remove unnecessary wire jogs.</span>
                    <span class="n">segments</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="n">remove_jogs</span><span class="p">(</span>
                        <span class="n">net</span><span class="p">,</span> <span class="n">segments</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="p">,</span> <span class="n">net_bboxes</span><span class="p">,</span> <span class="n">part_bboxes</span>
                    <span class="p">)</span>

                    <span class="c1"># Keep only non zero-length segments.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">!=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span>

                    <span class="c1"># Merge segments made colinear by removing jogs.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="n">merge_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

                    <span class="c1"># Split intersecting segments.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="n">split_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">,</span> <span class="n">net_pin_pts</span><span class="p">[</span><span class="n">net</span><span class="p">])</span>

                    <span class="c1"># Keep only non zero-length segments.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">segments</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span> <span class="o">!=</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="p">]</span>

                    <span class="c1"># Trim wire stubs caused by removing jogs.</span>
                    <span class="n">segments</span> <span class="o">=</span> <span class="n">trim_stubs</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

                    <span class="k">if</span> <span class="n">stop</span><span class="p">:</span>
                        <span class="c1"># Break from loop once net segments can no longer be improved.</span>
                        <span class="k">break</span>

                    <span class="c1"># Recalculate the net bounding box after modifying its segments.</span>
                    <span class="n">net_bboxes</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="n">segments_bbox</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

                    <span class="n">keep_cleaning</span> <span class="o">=</span> <span class="kc">True</span>

                <span class="c1"># Merge segments made colinear by removing jogs.</span>
                <span class="n">segments</span> <span class="o">=</span> <span class="n">merge_segments</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>

                <span class="c1"># Update the node net&#39;s wire with the cleaned version.</span>
                <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="n">segments</span></div>


<div class="viewcode-block" id="Router.add_junctions">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.add_junctions">[docs]</a>
    <span class="k">def</span> <span class="nf">add_junctions</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add X &amp; T-junctions where wire segments in the same net meet.&quot;&quot;&quot;</span>

        <span class="k">def</span> <span class="nf">find_junctions</span><span class="p">(</span><span class="n">route</span><span class="p">):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Find junctions where segments of a net intersect.</span>

<span class="sd">            Args:</span>
<span class="sd">                route (List): List of Segment objects.</span>

<span class="sd">            Returns:</span>
<span class="sd">                List: List of Points, one for each junction.</span>

<span class="sd">            Notes:</span>
<span class="sd">                You must run merge_segments() before finding junctions</span>
<span class="sd">                or else the segment endpoints might not be ordered</span>
<span class="sd">                correctly with p1 &lt; p2.</span>
<span class="sd">            &quot;&quot;&quot;</span>

            <span class="c1"># Separate route into vertical and horizontal segments.</span>
            <span class="n">horz_segs</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">route</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">]</span>
            <span class="n">vert_segs</span> <span class="o">=</span> <span class="p">[</span><span class="n">seg</span> <span class="k">for</span> <span class="n">seg</span> <span class="ow">in</span> <span class="n">route</span> <span class="k">if</span> <span class="n">seg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">seg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">]</span>

            <span class="n">junctions</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># Check each pair of horz/vert segments for an intersection, except</span>
            <span class="c1"># where they form a right-angle turn.</span>
            <span class="k">for</span> <span class="n">hseg</span> <span class="ow">in</span> <span class="n">horz_segs</span><span class="p">:</span>
                <span class="n">hseg_y</span> <span class="o">=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span>  <span class="c1"># Horz seg Y coord.</span>
                <span class="k">for</span> <span class="n">vseg</span> <span class="ow">in</span> <span class="n">vert_segs</span><span class="p">:</span>
                    <span class="n">vseg_x</span> <span class="o">=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span>  <span class="c1"># Vert seg X coord.</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">vseg_x</span> <span class="o">&lt;</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span>
                        <span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;=</span> <span class="n">hseg_y</span> <span class="o">&lt;=</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span>
                    <span class="p">):</span>
                        <span class="c1"># The vert segment intersects the interior of the horz seg.</span>
                        <span class="n">junctions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="n">vseg_x</span><span class="p">,</span> <span class="n">hseg_y</span><span class="p">))</span>
                    <span class="k">elif</span> <span class="p">(</span><span class="n">vseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">hseg_y</span> <span class="o">&lt;</span> <span class="n">vseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">y</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span>
                        <span class="n">hseg</span><span class="o">.</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">&lt;=</span> <span class="n">vseg_x</span> <span class="o">&lt;=</span> <span class="n">hseg</span><span class="o">.</span><span class="n">p2</span><span class="o">.</span><span class="n">x</span>
                    <span class="p">):</span>
                        <span class="c1"># The horz segment intersects the interior of the vert seg.</span>
                        <span class="n">junctions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="n">vseg_x</span><span class="p">,</span> <span class="n">hseg_y</span><span class="p">))</span>

            <span class="k">return</span> <span class="n">junctions</span>

        <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">segments</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">wires</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># Add X &amp; T-junctions between segments in the same net.</span>
            <span class="n">junctions</span> <span class="o">=</span> <span class="n">find_junctions</span><span class="p">(</span><span class="n">segments</span><span class="p">)</span>
            <span class="n">node</span><span class="o">.</span><span class="n">junctions</span><span class="p">[</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">junctions</span><span class="p">)</span></div>


<div class="viewcode-block" id="Router.rmv_routing_stuff">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.rmv_routing_stuff">[docs]</a>
    <span class="k">def</span> <span class="nf">rmv_routing_stuff</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove attributes added to parts/pins during routing.&quot;&quot;&quot;</span>

        <span class="n">rmv_attr</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;left_track&quot;</span><span class="p">,</span> <span class="s2">&quot;right_track&quot;</span><span class="p">,</span> <span class="s2">&quot;top_track&quot;</span><span class="p">,</span> <span class="s2">&quot;bottom_track&quot;</span><span class="p">))</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="n">rmv_attr</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">pins</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;route_pt&quot;</span><span class="p">,</span> <span class="s2">&quot;face&quot;</span><span class="p">))</span></div>


<div class="viewcode-block" id="Router.route">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.route.html#skidl.schematics.route.Router.route">[docs]</a>
    <span class="k">def</span> <span class="nf">route</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">tool</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Route the wires between part pins in this node and its children.</span>

<span class="sd">        Steps:</span>
<span class="sd">            1. Divide the bounding box surrounding the parts into switchboxes.</span>
<span class="sd">            2. Do global routing of nets through sequences of switchboxes.</span>
<span class="sd">            3. Do detailed routing within each switchbox.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Hierarchical node containing the parts to be connected.</span>
<span class="sd">            tool (str): Backend tool for schematics.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values:</span>
<span class="sd">                &quot;allow_routing_failure&quot;, &quot;draw&quot;, &quot;draw_all_terminals&quot;, &quot;show_capacities&quot;,</span>
<span class="sd">                &quot;draw_switchbox&quot;, &quot;draw_routing&quot;, &quot;draw_channels&quot;</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Inject the constants for the backend tool into this module.</span>
        <span class="kn">import</span> <span class="nn">skidl</span>
        <span class="kn">from</span> <span class="nn">skidl.tools</span> <span class="kn">import</span> <span class="n">tool_modules</span>

        <span class="n">tool</span> <span class="o">=</span> <span class="n">tool</span> <span class="ow">or</span> <span class="n">skidl</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">tool</span>
        <span class="n">this_module</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="vm">__name__</span><span class="p">]</span>
        <span class="n">this_module</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">tool_modules</span><span class="p">[</span><span class="n">tool</span><span class="p">]</span><span class="o">.</span><span class="n">constants</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>

        <span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;seed&quot;</span><span class="p">))</span>

        <span class="c1"># Remove any stuff leftover from a previous place &amp; route run.</span>
        <span class="n">node</span><span class="o">.</span><span class="n">rmv_routing_stuff</span><span class="p">()</span>

        <span class="c1"># First, recursively route any children of this node.</span>
        <span class="c1"># TODO: Child nodes are independent so could they be processed in parallel?</span>
        <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="n">child</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="n">tool</span><span class="o">=</span><span class="n">tool</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Exit if no parts to route in this node.</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="k">return</span>

        <span class="c1"># Get all the nets that have one or more pins within this node.</span>
        <span class="n">internal_nets</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_nets</span><span class="p">()</span>

        <span class="c1"># Exit if no nets to route.</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">internal_nets</span><span class="p">:</span>
            <span class="k">return</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># Extend routing points of part pins to the edges of their bounding boxes.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">add_routing_points</span><span class="p">(</span><span class="n">internal_nets</span><span class="p">)</span>

            <span class="c1"># Create the surrounding box that contains the entire routing area.</span>
            <span class="n">channel_sz</span> <span class="o">=</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">internal_nets</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">GRID</span>
            <span class="n">routing_bbox</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">node</span><span class="o">.</span><span class="n">internal_bbox</span><span class="p">()</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="n">channel_sz</span><span class="p">,</span> <span class="n">channel_sz</span><span class="p">))</span>
            <span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">()</span>

            <span class="c1"># Create horizontal &amp; vertical global routing tracks and faces.</span>
            <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">create_routing_tracks</span><span class="p">(</span><span class="n">routing_bbox</span><span class="p">)</span>

            <span class="c1"># Create terminals on the faces in the routing tracks.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">create_terminals</span><span class="p">(</span><span class="n">internal_nets</span><span class="p">,</span> <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span><span class="p">)</span>

            <span class="c1"># Draw part outlines, routing tracks and terminals.</span>
            <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_routing_channels&quot;</span><span class="p">):</span>
                <span class="n">draw_routing</span><span class="p">(</span>
                    <span class="n">node</span><span class="p">,</span> <span class="n">routing_bbox</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span> <span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>

            <span class="c1"># Do global routing of nets internal to the node.</span>
            <span class="n">global_routes</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">global_router</span><span class="p">(</span><span class="n">internal_nets</span><span class="p">)</span>

            <span class="c1"># Convert the global face-to-face routes into terminals on the switchboxes.</span>
            <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">global_routes</span><span class="p">:</span>
                <span class="n">route</span><span class="o">.</span><span class="n">cvt_faces_to_terminals</span><span class="p">()</span>

            <span class="c1"># If enabled, draw the global routing for debug purposes.</span>
            <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_global_routing&quot;</span><span class="p">):</span>
                <span class="n">draw_routing</span><span class="p">(</span>
                    <span class="n">node</span><span class="p">,</span>
                    <span class="n">routing_bbox</span><span class="p">,</span>
                    <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span>
                    <span class="n">h_tracks</span><span class="p">,</span>
                    <span class="n">v_tracks</span><span class="p">,</span>
                    <span class="n">global_routes</span><span class="p">,</span>
                    <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>

            <span class="c1"># Create detailed wiring using switchbox routing for the global routes.</span>
            <span class="n">switchboxes</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">create_switchboxes</span><span class="p">(</span><span class="n">h_tracks</span><span class="p">,</span> <span class="n">v_tracks</span><span class="p">)</span>

            <span class="c1"># Draw switchboxes and routing channels.</span>
            <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_assigned_terminals&quot;</span><span class="p">):</span>
                <span class="n">draw_routing</span><span class="p">(</span>
                    <span class="n">node</span><span class="p">,</span>
                    <span class="n">routing_bbox</span><span class="p">,</span>
                    <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span>
                    <span class="n">switchboxes</span><span class="p">,</span>
                    <span class="n">global_routes</span><span class="p">,</span>
                    <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>

            <span class="n">node</span><span class="o">.</span><span class="n">switchbox_router</span><span class="p">(</span><span class="n">switchboxes</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># If enabled, draw the global and detailed routing for debug purposes.</span>
            <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_switchbox_routing&quot;</span><span class="p">):</span>
                <span class="n">draw_routing</span><span class="p">(</span>
                    <span class="n">node</span><span class="p">,</span>
                    <span class="n">routing_bbox</span><span class="p">,</span>
                    <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span>
                    <span class="n">global_routes</span><span class="p">,</span>
                    <span class="n">switchboxes</span><span class="p">,</span>
                    <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>

            <span class="c1"># Now clean-up the wires and add junctions.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">cleanup_wires</span><span class="p">()</span>
            <span class="n">node</span><span class="o">.</span><span class="n">add_junctions</span><span class="p">()</span>

            <span class="c1"># If enabled, draw the global and detailed routing for debug purposes.</span>
            <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_switchbox_routing&quot;</span><span class="p">):</span>
                <span class="n">draw_routing</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">routing_bbox</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># Remove any stuff leftover from this place &amp; route run.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">rmv_routing_stuff</span><span class="p">()</span>

        <span class="k">except</span> <span class="n">RoutingFailure</span><span class="p">:</span>
            <span class="c1"># Remove any stuff leftover from this place &amp; route run.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">rmv_routing_stuff</span><span class="p">()</span>
            <span class="k">raise</span> <span class="n">RoutingFailure</span></div>
</div>

</pre></div>

            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="Main">
        <div class="sphinxsidebarwrapper">
<search id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="Related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../../genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="../../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../../index.html">SKiDL 2.2.0 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.schematics.route</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
    &#169; Copyright 2016-2025, Dave Vandenbout.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
    </div>
  </body>
</html>